streamlit-nightly 1.45.1.dev20250505__py3-none-any.whl → 1.45.1.dev20250507__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 -1
- streamlit/column_config.py +3 -1
- streamlit/commands/execution_control.py +3 -1
- streamlit/commands/logo.py +7 -2
- streamlit/connections/base_connection.py +2 -2
- streamlit/connections/snowflake_connection.py +4 -3
- streamlit/dataframe_util.py +2 -1
- streamlit/delta_generator.py +15 -35
- streamlit/elements/arrow.py +3 -3
- streamlit/elements/deck_gl_json_chart.py +1 -1
- streamlit/elements/exception.py +5 -1
- streamlit/elements/layouts.py +3 -9
- streamlit/elements/lib/column_types.py +2 -2
- streamlit/elements/lib/dialog.py +2 -1
- streamlit/elements/lib/js_number.py +4 -4
- streamlit/elements/lib/options_selector_utils.py +8 -5
- streamlit/elements/media.py +8 -7
- streamlit/elements/vega_charts.py +2 -2
- streamlit/elements/widgets/button.py +5 -6
- streamlit/elements/widgets/number_input.py +81 -28
- streamlit/elements/widgets/slider.py +87 -35
- streamlit/errors.py +9 -6
- streamlit/runtime/caching/cache_data_api.py +7 -9
- streamlit/runtime/caching/storage/cache_storage_protocol.py +1 -1
- streamlit/runtime/credentials.py +3 -3
- streamlit/runtime/fragment.py +2 -2
- streamlit/runtime/metrics_util.py +2 -2
- streamlit/runtime/runtime.py +1 -1
- streamlit/runtime/runtime_util.py +2 -1
- streamlit/runtime/scriptrunner/script_runner.py +3 -3
- streamlit/runtime/scriptrunner_utils/script_run_context.py +1 -0
- streamlit/runtime/secrets.py +14 -7
- streamlit/runtime/state/query_params.py +8 -8
- streamlit/runtime/state/session_state.py +8 -1
- streamlit/string_util.py +8 -5
- streamlit/web/bootstrap.py +2 -2
- streamlit/web/cli.py +2 -1
- streamlit/web/server/browser_websocket_handler.py +3 -2
- streamlit/web/server/component_request_handler.py +7 -7
- streamlit/web/server/media_file_handler.py +2 -2
- streamlit/web/server/oauth_authlib_routes.py +3 -3
- streamlit/web/server/routes.py +2 -2
- streamlit/web/server/server.py +4 -4
- streamlit/web/server/upload_file_request_handler.py +4 -3
- streamlit/web/server/websocket_headers.py +1 -1
- {streamlit_nightly-1.45.1.dev20250505.dist-info → streamlit_nightly-1.45.1.dev20250507.dist-info}/METADATA +1 -1
- {streamlit_nightly-1.45.1.dev20250505.dist-info → streamlit_nightly-1.45.1.dev20250507.dist-info}/RECORD +51 -51
- {streamlit_nightly-1.45.1.dev20250505.data → streamlit_nightly-1.45.1.dev20250507.data}/scripts/streamlit.cmd +0 -0
- {streamlit_nightly-1.45.1.dev20250505.dist-info → streamlit_nightly-1.45.1.dev20250507.dist-info}/WHEEL +0 -0
- {streamlit_nightly-1.45.1.dev20250505.dist-info → streamlit_nightly-1.45.1.dev20250507.dist-info}/entry_points.txt +0 -0
- {streamlit_nightly-1.45.1.dev20250505.dist-info → streamlit_nightly-1.45.1.dev20250507.dist-info}/top_level.txt +0 -0
@@ -201,10 +201,6 @@ class SliderSerde:
|
|
201
201
|
|
202
202
|
|
203
203
|
class SliderMixin:
|
204
|
-
# For easier readability, all the arguments with un-changing types across these overload signatures have been
|
205
|
-
# collapsed onto a single line.
|
206
|
-
|
207
|
-
# fmt: off
|
208
204
|
# If min/max/value/step are not provided, then we return an int.
|
209
205
|
# if ONLY step is provided, then it must be an int and we return an int.
|
210
206
|
@overload
|
@@ -213,11 +209,18 @@ class SliderMixin:
|
|
213
209
|
label: str,
|
214
210
|
min_value: None = None,
|
215
211
|
max_value: None = None,
|
216
|
-
value:
|
212
|
+
value: None = None,
|
217
213
|
step: int | None = None,
|
218
|
-
format: str | None = None,
|
219
|
-
|
220
|
-
|
214
|
+
format: str | None = None,
|
215
|
+
key: Key | None = None,
|
216
|
+
help: str | None = None,
|
217
|
+
on_change: WidgetCallback | None = None,
|
218
|
+
args: WidgetArgs | None = None,
|
219
|
+
kwargs: WidgetKwargs | None = None,
|
220
|
+
*,
|
221
|
+
disabled: bool = False,
|
222
|
+
label_visibility: LabelVisibility = "visible",
|
223
|
+
) -> int: ...
|
221
224
|
|
222
225
|
# If min-value or max_value is provided and a numeric type, and value (if provided)
|
223
226
|
# is a singular numeric, return the same numeric type.
|
@@ -229,9 +232,16 @@ class SliderMixin:
|
|
229
232
|
max_value: SliderNumericT | None = None,
|
230
233
|
value: SliderNumericT | None = None,
|
231
234
|
step: StepNumericT[SliderNumericT] | None = None,
|
232
|
-
format: str | None = None,
|
233
|
-
|
234
|
-
|
235
|
+
format: str | None = None,
|
236
|
+
key: Key | None = None,
|
237
|
+
help: str | None = None,
|
238
|
+
on_change: WidgetCallback | None = None,
|
239
|
+
args: WidgetArgs | None = None,
|
240
|
+
kwargs: WidgetKwargs | None = None,
|
241
|
+
*,
|
242
|
+
disabled: bool = False,
|
243
|
+
label_visibility: LabelVisibility = "visible",
|
244
|
+
) -> SliderNumericT: ...
|
235
245
|
|
236
246
|
# If value is provided and a sequence of numeric type,
|
237
247
|
# return a tuple of the same numeric type.
|
@@ -244,9 +254,15 @@ class SliderMixin:
|
|
244
254
|
*,
|
245
255
|
value: SliderNumericSpanT[SliderNumericT],
|
246
256
|
step: StepNumericT[SliderNumericT] | None = None,
|
247
|
-
format: str | None = None,
|
248
|
-
|
249
|
-
|
257
|
+
format: str | None = None,
|
258
|
+
key: Key | None = None,
|
259
|
+
help: str | None = None,
|
260
|
+
on_change: WidgetCallback | None = None,
|
261
|
+
args: WidgetArgs | None = None,
|
262
|
+
kwargs: WidgetKwargs | None = None,
|
263
|
+
disabled: bool = False,
|
264
|
+
label_visibility: LabelVisibility = "visible",
|
265
|
+
) -> tuple[SliderNumericT, SliderNumericT]: ...
|
250
266
|
|
251
267
|
# If value is provided positionally and a sequence of numeric type,
|
252
268
|
# return a tuple of the same numeric type.
|
@@ -257,11 +273,17 @@ class SliderMixin:
|
|
257
273
|
min_value: SliderNumericT,
|
258
274
|
max_value: SliderNumericT,
|
259
275
|
value: SliderNumericSpanT[SliderNumericT],
|
260
|
-
/,
|
261
276
|
step: StepNumericT[SliderNumericT] | None = None,
|
262
|
-
format: str | None = None,
|
263
|
-
|
264
|
-
|
277
|
+
format: str | None = None,
|
278
|
+
key: Key | None = None,
|
279
|
+
help: str | None = None,
|
280
|
+
on_change: WidgetCallback | None = None,
|
281
|
+
args: WidgetArgs | None = None,
|
282
|
+
kwargs: WidgetKwargs | None = None,
|
283
|
+
*,
|
284
|
+
disabled: bool = False,
|
285
|
+
label_visibility: LabelVisibility = "visible",
|
286
|
+
) -> tuple[SliderNumericT, SliderNumericT]: ...
|
265
287
|
|
266
288
|
# If min-value is provided and a datelike type, and value (if provided)
|
267
289
|
# is a singular datelike, return the same datelike type.
|
@@ -273,9 +295,16 @@ class SliderMixin:
|
|
273
295
|
max_value: SliderDatelikeT | None = None,
|
274
296
|
value: SliderDatelikeT | None = None,
|
275
297
|
step: StepDatelikeT | None = None,
|
276
|
-
format: str | None = None,
|
277
|
-
|
278
|
-
|
298
|
+
format: str | None = None,
|
299
|
+
key: Key | None = None,
|
300
|
+
help: str | None = None,
|
301
|
+
on_change: WidgetCallback | None = None,
|
302
|
+
args: WidgetArgs | None = None,
|
303
|
+
kwargs: WidgetKwargs | None = None,
|
304
|
+
*,
|
305
|
+
disabled: bool = False,
|
306
|
+
label_visibility: LabelVisibility = "visible",
|
307
|
+
) -> SliderDatelikeT: ...
|
279
308
|
|
280
309
|
# If max-value is provided and a datelike type, and value (if provided)
|
281
310
|
# is a singular datelike, return the same datelike type.
|
@@ -288,9 +317,15 @@ class SliderMixin:
|
|
288
317
|
max_value: SliderDatelikeT,
|
289
318
|
value: SliderDatelikeT | None = None,
|
290
319
|
step: StepDatelikeT | None = None,
|
291
|
-
format: str | None = None,
|
292
|
-
|
293
|
-
|
320
|
+
format: str | None = None,
|
321
|
+
key: Key | None = None,
|
322
|
+
help: str | None = None,
|
323
|
+
on_change: WidgetCallback | None = None,
|
324
|
+
args: WidgetArgs | None = None,
|
325
|
+
kwargs: WidgetKwargs | None = None,
|
326
|
+
disabled: bool = False,
|
327
|
+
label_visibility: LabelVisibility = "visible",
|
328
|
+
) -> SliderDatelikeT: ...
|
294
329
|
|
295
330
|
# If value is provided and a datelike type, return the same datelike type.
|
296
331
|
@overload
|
@@ -302,9 +337,15 @@ class SliderMixin:
|
|
302
337
|
*,
|
303
338
|
value: SliderDatelikeT,
|
304
339
|
step: StepDatelikeT | None = None,
|
305
|
-
format: str | None = None,
|
306
|
-
|
307
|
-
|
340
|
+
format: str | None = None,
|
341
|
+
key: Key | None = None,
|
342
|
+
help: str | None = None,
|
343
|
+
on_change: WidgetCallback | None = None,
|
344
|
+
args: WidgetArgs | None = None,
|
345
|
+
kwargs: WidgetKwargs | None = None,
|
346
|
+
disabled: bool = False,
|
347
|
+
label_visibility: LabelVisibility = "visible",
|
348
|
+
) -> SliderDatelikeT: ...
|
308
349
|
|
309
350
|
# If value is provided and a sequence of datelike type,
|
310
351
|
# return a tuple of the same datelike type.
|
@@ -317,9 +358,15 @@ class SliderMixin:
|
|
317
358
|
*,
|
318
359
|
value: SliderDatelikeSpanT[SliderDatelikeT],
|
319
360
|
step: StepDatelikeT | None = None,
|
320
|
-
format: str | None = None,
|
321
|
-
|
322
|
-
|
361
|
+
format: str | None = None,
|
362
|
+
key: Key | None = None,
|
363
|
+
help: str | None = None,
|
364
|
+
on_change: WidgetCallback | None = None,
|
365
|
+
args: WidgetArgs | None = None,
|
366
|
+
kwargs: WidgetKwargs | None = None,
|
367
|
+
disabled: bool = False,
|
368
|
+
label_visibility: LabelVisibility = "visible",
|
369
|
+
) -> tuple[SliderDatelikeT, SliderDatelikeT]: ...
|
323
370
|
|
324
371
|
# If value is provided positionally and a sequence of datelike type,
|
325
372
|
# return a tuple of the same datelike type.
|
@@ -332,11 +379,16 @@ class SliderMixin:
|
|
332
379
|
value: SliderDatelikeSpanT[SliderDatelikeT],
|
333
380
|
/,
|
334
381
|
step: StepDatelikeT | None = None,
|
335
|
-
format: str | None = None,
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
382
|
+
format: str | None = None,
|
383
|
+
key: Key | None = None,
|
384
|
+
help: str | None = None,
|
385
|
+
on_change: WidgetCallback | None = None,
|
386
|
+
args: WidgetArgs | None = None,
|
387
|
+
kwargs: WidgetKwargs | None = None,
|
388
|
+
*,
|
389
|
+
disabled: bool = False,
|
390
|
+
label_visibility: LabelVisibility = "visible",
|
391
|
+
) -> tuple[SliderDatelikeT, SliderDatelikeT]: ...
|
340
392
|
|
341
393
|
# https://github.com/python/mypy/issues/17614
|
342
394
|
@gather_metrics("slider") # type: ignore[misc]
|
streamlit/errors.py
CHANGED
@@ -49,7 +49,7 @@ class FragmentStorageKeyError(Error, KeyError):
|
|
49
49
|
pass
|
50
50
|
|
51
51
|
|
52
|
-
class FragmentHandledException(Exception):
|
52
|
+
class FragmentHandledException(Exception): # noqa: N818
|
53
53
|
"""An exception that is raised by the fragment
|
54
54
|
when it has handled the exception itself.
|
55
55
|
"""
|
@@ -57,15 +57,15 @@ class FragmentHandledException(Exception):
|
|
57
57
|
pass
|
58
58
|
|
59
59
|
|
60
|
-
class NoStaticFiles(Error):
|
60
|
+
class NoStaticFiles(Error): # noqa: N818
|
61
61
|
pass
|
62
62
|
|
63
63
|
|
64
|
-
class NoSessionContext(Error):
|
64
|
+
class NoSessionContext(Error): # noqa: N818
|
65
65
|
pass
|
66
66
|
|
67
67
|
|
68
|
-
class MarkdownFormattedException(Error):
|
68
|
+
class MarkdownFormattedException(Error): # noqa: N818
|
69
69
|
"""Exceptions with Markdown in their description.
|
70
70
|
|
71
71
|
Instances of this class can use markdown in their messages, which will get
|
@@ -199,7 +199,8 @@ class StreamlitInvalidSidebarStateError(LocalizableStreamlitException):
|
|
199
199
|
|
200
200
|
def __init__(self, initial_sidebar_state: str):
|
201
201
|
super().__init__(
|
202
|
-
'`initial_sidebar_state` must be `"auto"` or `"expanded"` or
|
202
|
+
'`initial_sidebar_state` must be `"auto"` or `"expanded"` or '
|
203
|
+
'`"collapsed"` (got `"{initial_sidebar_state}"`)',
|
203
204
|
initial_sidebar_state=initial_sidebar_state,
|
204
205
|
)
|
205
206
|
|
@@ -413,7 +414,9 @@ class StreamlitFragmentWidgetsNotAllowedOutsideError(LocalizableStreamlitExcepti
|
|
413
414
|
|
414
415
|
|
415
416
|
class StreamlitInvalidFormCallbackError(LocalizableStreamlitException):
|
416
|
-
"""Exception raised a `on_change` callback is set on any element in a form except for
|
417
|
+
"""Exception raised a `on_change` callback is set on any element in a form except for
|
418
|
+
the `st.form_submit_button`.
|
419
|
+
"""
|
417
420
|
|
418
421
|
def __init__(self):
|
419
422
|
super().__init__(
|
@@ -57,7 +57,7 @@ from streamlit.runtime.caching.storage import (
|
|
57
57
|
CacheStorageManager,
|
58
58
|
)
|
59
59
|
from streamlit.runtime.caching.storage.cache_storage_protocol import (
|
60
|
-
|
60
|
+
InvalidCacheStorageContextError,
|
61
61
|
)
|
62
62
|
from streamlit.runtime.caching.storage.dummy_cache_storage import (
|
63
63
|
MemoryCacheStorageManager,
|
@@ -270,12 +270,11 @@ class DataCaches(CacheStatsProvider):
|
|
270
270
|
)
|
271
271
|
try:
|
272
272
|
self.get_storage_manager().check_context(cache_context)
|
273
|
-
except
|
274
|
-
_LOGGER.
|
273
|
+
except InvalidCacheStorageContextError:
|
274
|
+
_LOGGER.exception(
|
275
275
|
"Cache params for function %s are incompatible with current "
|
276
276
|
"cache storage manager.",
|
277
277
|
function_name,
|
278
|
-
exc_info=e,
|
279
278
|
)
|
280
279
|
raise
|
281
280
|
|
@@ -298,11 +297,10 @@ class DataCaches(CacheStatsProvider):
|
|
298
297
|
def get_storage_manager(self) -> CacheStorageManager:
|
299
298
|
if runtime.exists():
|
300
299
|
return runtime.get_instance().cache_storage_manager
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
return MemoryCacheStorageManager()
|
300
|
+
# When running in "raw mode", we can't access the CacheStorageManager,
|
301
|
+
# so we're falling back to InMemoryCache.
|
302
|
+
_LOGGER.warning("No runtime found, using MemoryCacheStorageManager")
|
303
|
+
return MemoryCacheStorageManager()
|
306
304
|
|
307
305
|
|
308
306
|
# Singleton DataCaches instance
|
@@ -68,7 +68,7 @@ class CacheStorageKeyNotFoundError(CacheStorageError):
|
|
68
68
|
"""Raised when the key is not found in the cache storage."""
|
69
69
|
|
70
70
|
|
71
|
-
class
|
71
|
+
class InvalidCacheStorageContextError(CacheStorageError):
|
72
72
|
"""Raised if the cache storage manager is not able to work with
|
73
73
|
provided CacheStorageContext.
|
74
74
|
"""
|
streamlit/runtime/credentials.py
CHANGED
@@ -79,7 +79,7 @@ def _send_email(email: str) -> None:
|
|
79
79
|
).json()
|
80
80
|
metrics_url = response_json.get("url", "")
|
81
81
|
except Exception:
|
82
|
-
_LOGGER.
|
82
|
+
_LOGGER.exception("Failed to fetch metrics URL")
|
83
83
|
return
|
84
84
|
|
85
85
|
headers = {
|
@@ -150,7 +150,7 @@ class Credentials:
|
|
150
150
|
with open(self._conf_file) as f:
|
151
151
|
data = toml.load(f).get("general")
|
152
152
|
if data is None:
|
153
|
-
raise
|
153
|
+
raise RuntimeError # noqa: TRY301
|
154
154
|
self.activation = _verify_email(data.get("email"))
|
155
155
|
except FileNotFoundError:
|
156
156
|
if auto_resolve:
|
@@ -164,7 +164,7 @@ class Credentials:
|
|
164
164
|
self.reset()
|
165
165
|
self.activate(show_instructions=not auto_resolve)
|
166
166
|
return
|
167
|
-
raise
|
167
|
+
raise RuntimeError(
|
168
168
|
textwrap.dedent(
|
169
169
|
"""
|
170
170
|
Unable to load credentials from %s.
|
streamlit/runtime/fragment.py
CHANGED
@@ -246,11 +246,11 @@ def _fragment(
|
|
246
246
|
except (
|
247
247
|
RerunException,
|
248
248
|
StopException,
|
249
|
-
)
|
249
|
+
):
|
250
250
|
# The wrapped_fragment function is executed
|
251
251
|
# inside of a exec_func_with_error_handling call, so
|
252
252
|
# there is a correct handler for these exceptions.
|
253
|
-
raise
|
253
|
+
raise
|
254
254
|
except Exception as e:
|
255
255
|
# render error here so that the delta path is correct
|
256
256
|
# for full app runs, the error will be displayed by the
|
@@ -442,12 +442,12 @@ def gather_metrics(name: str, func: F | None = None) -> Callable[[F], F] | F:
|
|
442
442
|
_LOGGER.debug("Failed to collect command telemetry", exc_info=ex)
|
443
443
|
try:
|
444
444
|
result = non_optional_func(*args, **kwargs)
|
445
|
-
except RerunException
|
445
|
+
except RerunException:
|
446
446
|
# Duplicated from below, because static analysis tools get confused
|
447
447
|
# by deferring the rethrow.
|
448
448
|
if tracking_activated and command_telemetry:
|
449
449
|
command_telemetry.time = to_microseconds(timer() - exec_start)
|
450
|
-
raise
|
450
|
+
raise
|
451
451
|
finally:
|
452
452
|
# Activate tracking again if command executes without any exceptions
|
453
453
|
# we only want to do that if this command has set the
|
streamlit/runtime/runtime.py
CHANGED
@@ -596,7 +596,7 @@ class Runtime:
|
|
596
596
|
elif self._state == RuntimeState.ONE_OR_MORE_SESSIONS_CONNECTED:
|
597
597
|
pass
|
598
598
|
else:
|
599
|
-
raise RuntimeError(f"Bad Runtime state at start: {self._state}")
|
599
|
+
raise RuntimeError(f"Bad Runtime state at start: {self._state}") # noqa: TRY301
|
600
600
|
|
601
601
|
# Signal that we're started and ready to accept sessions
|
602
602
|
async_objs.started.set_result(None)
|
@@ -39,7 +39,8 @@ class MessageSizeError(MarkdownFormattedException):
|
|
39
39
|
# This needs to have zero indentation otherwise the markdown will render incorrectly.
|
40
40
|
return (
|
41
41
|
f"""
|
42
|
-
**Data of size {len(failed_msg_str) / 1e6:.1f} MB exceeds the message size limit of
|
42
|
+
**Data of size {len(failed_msg_str) / 1e6:.1f} MB exceeds the message size limit of
|
43
|
+
{get_max_message_size_bytes() / 1e6} MB.**
|
43
44
|
|
44
45
|
This is often caused by a large chart or dataframe. Please decrease the amount of data sent
|
45
46
|
to the browser, or increase the limit by setting the config option `server.maxMessageSize`.
|
@@ -297,7 +297,7 @@ class ScriptRunner:
|
|
297
297
|
|
298
298
|
"""
|
299
299
|
if self._script_thread is not None:
|
300
|
-
raise
|
300
|
+
raise RuntimeError("ScriptRunner was already started")
|
301
301
|
|
302
302
|
self._script_thread = threading.Thread(
|
303
303
|
target=self._run_script_thread,
|
@@ -626,11 +626,11 @@ class ScriptRunner:
|
|
626
626
|
" Usually this doesn't happen or no action is"
|
627
627
|
" required, so its mainly for debugging."
|
628
628
|
)
|
629
|
-
except (RerunException, StopException)
|
629
|
+
except (RerunException, StopException):
|
630
630
|
# The wrapped_fragment function is executed
|
631
631
|
# inside of a exec_func_with_error_handling call, so
|
632
632
|
# there is a correct handler for these exceptions.
|
633
|
-
raise
|
633
|
+
raise
|
634
634
|
except Exception: # noqa: S110
|
635
635
|
# Ignore exceptions raised by fragments here as we don't
|
636
636
|
# want to stop the execution of other fragments. The
|
@@ -107,6 +107,7 @@ class ScriptRunContext:
|
|
107
107
|
current_fragment_id: str | None = None
|
108
108
|
fragment_ids_this_run: list[str] | None = None
|
109
109
|
new_fragment_ids: set[str] = field(default_factory=set)
|
110
|
+
in_fragment_callback: bool = False
|
110
111
|
_active_script_hash: str = ""
|
111
112
|
# we allow only one dialog to be open at the same time
|
112
113
|
has_dialog_opened: bool = False
|
streamlit/runtime/secrets.py
CHANGED
@@ -37,7 +37,9 @@ _LOGGER: Final = get_logger(__name__)
|
|
37
37
|
|
38
38
|
|
39
39
|
class SecretErrorMessages:
|
40
|
-
"""SecretErrorMessages stores all error messages we use for secrets to allow customization
|
40
|
+
"""SecretErrorMessages stores all error messages we use for secrets to allow customization
|
41
|
+
for different environments.
|
42
|
+
|
41
43
|
For example Streamlit Cloud can customize the message to be different than the open source.
|
42
44
|
|
43
45
|
For internal use, may change in future releases without notice.
|
@@ -46,13 +48,15 @@ class SecretErrorMessages:
|
|
46
48
|
def __init__(self):
|
47
49
|
self.missing_attr_message = lambda attr_name: (
|
48
50
|
f'st.secrets has no attribute "{attr_name}". '
|
49
|
-
|
50
|
-
|
51
|
+
"Did you forget to add it to secrets.toml, mount it to secret directory, or the app settings "
|
52
|
+
"on Streamlit Cloud? More info: "
|
53
|
+
"https://docs.streamlit.io/deploy/streamlit-community-cloud/deploy-your-app/secrets-management"
|
51
54
|
)
|
52
55
|
self.missing_key_message = lambda key: (
|
53
56
|
f'st.secrets has no key "{key}". '
|
54
|
-
|
55
|
-
|
57
|
+
"Did you forget to add it to secrets.toml, mount it to secret directory, or the app settings "
|
58
|
+
"on Streamlit Cloud? More info: "
|
59
|
+
"https://docs.streamlit.io/deploy/streamlit-community-cloud/deploy-your-app/secrets-management"
|
56
60
|
)
|
57
61
|
self.no_secrets_found = lambda file_paths: (
|
58
62
|
f"No secrets found. Valid paths for a secrets.toml file or secret directories are: {', '.join(file_paths)}"
|
@@ -272,7 +276,8 @@ class Secrets(Mapping[str, Any]):
|
|
272
276
|
return secrets, found_secrets_file
|
273
277
|
|
274
278
|
def _parse_directory(self, path: str) -> tuple[Mapping[str, Any], bool]:
|
275
|
-
"""Parse a directory for secrets. Directory style can be used to support Kubernetes secrets that are
|
279
|
+
"""Parse a directory for secrets. Directory style can be used to support Kubernetes secrets that are
|
280
|
+
mounted to folders.
|
276
281
|
|
277
282
|
Example structure:
|
278
283
|
- top_level_secret_folder
|
@@ -380,7 +385,9 @@ class Secrets(Mapping[str, Any]):
|
|
380
385
|
return self._secrets
|
381
386
|
|
382
387
|
def to_dict(self) -> dict[str, Any]:
|
383
|
-
"""Converts the secrets store into a nested dictionary, where nested AttrDict objects are
|
388
|
+
"""Converts the secrets store into a nested dictionary, where nested AttrDict objects are
|
389
|
+
also converted into dictionaries.
|
390
|
+
"""
|
384
391
|
secrets = self._parse()
|
385
392
|
return _convert_to_dict(secrets)
|
386
393
|
|
@@ -58,17 +58,17 @@ class QueryParams(MutableMapping[str, str]):
|
|
58
58
|
If the key is not present, raise KeyError.
|
59
59
|
"""
|
60
60
|
self._ensure_single_query_api_used()
|
61
|
+
if key in EMBED_QUERY_PARAMS_KEYS:
|
62
|
+
raise KeyError(missing_key_error_message(key))
|
63
|
+
|
61
64
|
try:
|
62
|
-
if key in EMBED_QUERY_PARAMS_KEYS:
|
63
|
-
raise KeyError(missing_key_error_message(key))
|
64
65
|
value = self._query_params[key]
|
65
66
|
if isinstance(value, list):
|
66
67
|
if len(value) == 0:
|
67
68
|
return ""
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
return value[-1]
|
69
|
+
# Return the last value to mimic Tornado's behavior
|
70
|
+
# https://www.tornadoweb.org/en/stable/web.html#tornado.web.RequestHandler.get_query_argument
|
71
|
+
return value[-1]
|
72
72
|
return value
|
73
73
|
except KeyError:
|
74
74
|
raise KeyError(missing_key_error_message(key))
|
@@ -97,9 +97,9 @@ class QueryParams(MutableMapping[str, str]):
|
|
97
97
|
|
98
98
|
def __delitem__(self, key: str) -> None:
|
99
99
|
self._ensure_single_query_api_used()
|
100
|
+
if key in EMBED_QUERY_PARAMS_KEYS:
|
101
|
+
raise KeyError(missing_key_error_message(key))
|
100
102
|
try:
|
101
|
-
if key in EMBED_QUERY_PARAMS_KEYS:
|
102
|
-
raise KeyError(missing_key_error_message(key))
|
103
103
|
del self._query_params[key]
|
104
104
|
self._send_query_param_msg()
|
105
105
|
except KeyError:
|
@@ -269,7 +269,14 @@ class WStates(MutableMapping[str, Any]):
|
|
269
269
|
|
270
270
|
args = metadata.callback_args or ()
|
271
271
|
kwargs = metadata.callback_kwargs or {}
|
272
|
-
|
272
|
+
|
273
|
+
ctx = get_script_run_ctx()
|
274
|
+
if ctx and metadata.fragment_id is not None:
|
275
|
+
ctx.in_fragment_callback = True
|
276
|
+
callback(*args, **kwargs)
|
277
|
+
ctx.in_fragment_callback = False
|
278
|
+
else:
|
279
|
+
callback(*args, **kwargs)
|
273
280
|
|
274
281
|
|
275
282
|
def _missing_key_error_message(key: str) -> str:
|
streamlit/string_util.py
CHANGED
@@ -72,7 +72,8 @@ def validate_emoji(maybe_emoji: str | None) -> str:
|
|
72
72
|
return maybe_emoji
|
73
73
|
else:
|
74
74
|
raise StreamlitAPIException(
|
75
|
-
f'The value "{maybe_emoji}" is not a valid emoji. Shortcodes are not allowed,
|
75
|
+
f'The value "{maybe_emoji}" is not a valid emoji. Shortcodes are not allowed, '
|
76
|
+
"please use a single character instead."
|
76
77
|
)
|
77
78
|
|
78
79
|
|
@@ -97,8 +98,9 @@ def validate_material_icon(maybe_material_icon: str | None) -> str:
|
|
97
98
|
|
98
99
|
if not icon_match:
|
99
100
|
raise StreamlitAPIException(
|
100
|
-
f'The value `"{maybe_material_icon.replace("/", invisible_white_space + "/")}"` is
|
101
|
-
|
101
|
+
f'The value `"{maybe_material_icon.replace("/", invisible_white_space + "/")}"` is '
|
102
|
+
"not a valid Material icon. Please use a Material icon shortcode like "
|
103
|
+
f"**`:material{invisible_white_space}/thumb_up:`**"
|
102
104
|
)
|
103
105
|
|
104
106
|
pack_name, icon_name = icon_match.groups()
|
@@ -109,8 +111,9 @@ def validate_material_icon(maybe_material_icon: str | None) -> str:
|
|
109
111
|
or not is_material_icon(icon_name)
|
110
112
|
):
|
111
113
|
raise StreamlitAPIException(
|
112
|
-
f'The value `"{maybe_material_icon.replace("/", invisible_white_space + "/")}"` is not a
|
113
|
-
|
114
|
+
f'The value `"{maybe_material_icon.replace("/", invisible_white_space + "/")}"` is not a '
|
115
|
+
"valid Material icon. Please use a Material icon shortcode like "
|
116
|
+
f"**`:material{invisible_white_space}/thumb_up:`**."
|
114
117
|
)
|
115
118
|
|
116
119
|
return f":{pack_name}/{icon_name}:"
|
streamlit/web/bootstrap.py
CHANGED
@@ -112,8 +112,8 @@ def _on_server_start(server: Server) -> None:
|
|
112
112
|
# errors and display them here.
|
113
113
|
try:
|
114
114
|
secrets.load_if_toml_exists()
|
115
|
-
except Exception
|
116
|
-
_LOGGER.
|
115
|
+
except Exception:
|
116
|
+
_LOGGER.exception("Failed to load secrets.toml file")
|
117
117
|
|
118
118
|
def maybe_open_browser():
|
119
119
|
if config.get_option("server.headless"):
|
streamlit/web/cli.py
CHANGED
@@ -213,7 +213,8 @@ def main_run(target: str, args=None, **kwargs):
|
|
213
213
|
if extension[1:] not in ACCEPTED_FILE_EXTENSIONS:
|
214
214
|
if extension[1:] == "":
|
215
215
|
raise click.BadArgumentUsage(
|
216
|
-
"Streamlit requires raw Python (.py) files, but the provided file has no extension.\
|
216
|
+
"Streamlit requires raw Python (.py) files, but the provided file has no extension.\n"
|
217
|
+
"For more information, please see https://docs.streamlit.io"
|
217
218
|
)
|
218
219
|
else:
|
219
220
|
raise click.BadArgumentUsage(
|
@@ -115,7 +115,8 @@ class BrowserWebSocketHandler(WebSocketHandler, SessionClient):
|
|
115
115
|
|
116
116
|
else:
|
117
117
|
_LOGGER.error(
|
118
|
-
"Origin mismatch, the origin of websocket request is not the
|
118
|
+
"Origin mismatch, the origin of websocket request is not the "
|
119
|
+
"same origin of redirect_uri in secrets.toml",
|
119
120
|
)
|
120
121
|
|
121
122
|
return user_info
|
@@ -212,7 +213,7 @@ class BrowserWebSocketHandler(WebSocketHandler, SessionClient):
|
|
212
213
|
if isinstance(payload, str):
|
213
214
|
# Sanity check. (The frontend should only be sending us bytes;
|
214
215
|
# Protobuf.ParseFromString does not accept str input.)
|
215
|
-
raise
|
216
|
+
raise TypeError( # noqa: TRY301
|
216
217
|
"WebSocket received an unexpected `str` message. "
|
217
218
|
"(We expect `bytes` only.)"
|
218
219
|
)
|
@@ -55,9 +55,10 @@ class ComponentRequestHandler(tornado.web.RequestHandler):
|
|
55
55
|
try:
|
56
56
|
with open(abspath, "rb") as file:
|
57
57
|
contents = file.read()
|
58
|
-
except OSError
|
59
|
-
|
60
|
-
|
58
|
+
except OSError:
|
59
|
+
sanitized_abspath = abspath.replace("\n", "").replace("\r", "")
|
60
|
+
_LOGGER.exception(
|
61
|
+
"ComponentRequestHandler: GET %s read error", sanitized_abspath
|
61
62
|
)
|
62
63
|
self.write("read error")
|
63
64
|
self.set_status(404)
|
@@ -102,13 +103,12 @@ class ComponentRequestHandler(tornado.web.RequestHandler):
|
|
102
103
|
# As of 2015-07-21 there is no bzip2 encoding defined at
|
103
104
|
# http://www.iana.org/assignments/media-types/media-types.xhtml
|
104
105
|
# So for that (and any other encoding), use octet-stream.
|
105
|
-
|
106
|
+
if encoding is not None:
|
106
107
|
return "application/octet-stream"
|
107
|
-
|
108
|
+
if mime_type is not None:
|
108
109
|
return mime_type
|
109
110
|
# if mime_type not detected, use application/octet-stream
|
110
|
-
|
111
|
-
return "application/octet-stream"
|
111
|
+
return "application/octet-stream"
|
112
112
|
|
113
113
|
@staticmethod
|
114
114
|
def get_url(file_id: str) -> str:
|
@@ -87,7 +87,7 @@ class MediaFileHandler(tornado.web.StaticFileHandler):
|
|
87
87
|
try:
|
88
88
|
self._storage.get_file(absolute_path)
|
89
89
|
except MediaFileStorageError:
|
90
|
-
_LOGGER.
|
90
|
+
_LOGGER.exception("MediaFileHandler: Missing file %s", absolute_path)
|
91
91
|
raise tornado.web.HTTPError(404, "not found")
|
92
92
|
|
93
93
|
return absolute_path
|
@@ -121,7 +121,7 @@ class MediaFileHandler(tornado.web.StaticFileHandler):
|
|
121
121
|
# abspath is the hash as used `get_absolute_path`
|
122
122
|
media_file = cls._storage.get_file(abspath)
|
123
123
|
except Exception:
|
124
|
-
_LOGGER.
|
124
|
+
_LOGGER.exception("MediaFileHandler: Missing file %s", abspath)
|
125
125
|
return None
|
126
126
|
|
127
127
|
_LOGGER.debug(
|