streamlit-nightly 1.37.2.dev20240810__py2.py3-none-any.whl → 1.37.2.dev20240812__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 (27) hide show
  1. streamlit/dataframe_util.py +61 -2
  2. streamlit/delta_generator.py +3 -158
  3. streamlit/elements/arrow.py +146 -2
  4. streamlit/elements/deck_gl_json_chart.py +2 -2
  5. streamlit/elements/image.py +12 -7
  6. streamlit/elements/lib/built_in_chart_utils.py +12 -5
  7. streamlit/elements/lib/column_config_utils.py +8 -0
  8. streamlit/elements/lib/dialog.py +6 -3
  9. streamlit/elements/lib/mutable_status_container.py +3 -2
  10. streamlit/elements/media.py +11 -9
  11. streamlit/elements/metric.py +2 -2
  12. streamlit/runtime/caching/hashing.py +16 -5
  13. streamlit/runtime/scriptrunner/__init__.py +2 -0
  14. streamlit/runtime/scriptrunner/exec_code.py +1 -1
  15. streamlit/runtime/scriptrunner/script_run_context.py +18 -6
  16. streamlit/source_util.py +2 -7
  17. streamlit/static/asset-manifest.json +2 -2
  18. streamlit/static/index.html +1 -1
  19. streamlit/static/static/js/{main.80efcd23.js → main.d1c1e1f9.js} +2 -2
  20. streamlit/type_util.py +5 -0
  21. {streamlit_nightly-1.37.2.dev20240810.dist-info → streamlit_nightly-1.37.2.dev20240812.dist-info}/METADATA +1 -1
  22. {streamlit_nightly-1.37.2.dev20240810.dist-info → streamlit_nightly-1.37.2.dev20240812.dist-info}/RECORD +27 -27
  23. /streamlit/static/static/js/{main.80efcd23.js.LICENSE.txt → main.d1c1e1f9.js.LICENSE.txt} +0 -0
  24. {streamlit_nightly-1.37.2.dev20240810.data → streamlit_nightly-1.37.2.dev20240812.data}/scripts/streamlit.cmd +0 -0
  25. {streamlit_nightly-1.37.2.dev20240810.dist-info → streamlit_nightly-1.37.2.dev20240812.dist-info}/WHEEL +0 -0
  26. {streamlit_nightly-1.37.2.dev20240810.dist-info → streamlit_nightly-1.37.2.dev20240812.dist-info}/entry_points.txt +0 -0
  27. {streamlit_nightly-1.37.2.dev20240810.dist-info → streamlit_nightly-1.37.2.dev20240812.dist-info}/top_level.txt +0 -0
@@ -19,11 +19,14 @@ from typing import TYPE_CHECKING, Literal, cast
19
19
 
20
20
  from typing_extensions import Self, TypeAlias
21
21
 
22
- from streamlit.delta_generator import DeltaGenerator, _enqueue_message
22
+ 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 import get_script_run_ctx
26
+ from streamlit.runtime.scriptrunner.script_run_context import (
27
+ enqueue_message,
28
+ get_script_run_ctx,
29
+ )
27
30
 
28
31
  if TYPE_CHECKING:
29
32
  from types import TracebackType
@@ -127,7 +130,7 @@ class Dialog(DeltaGenerator):
127
130
  # We add a sleep here to give the web app time to react to the update. Otherwise,
128
131
  # we might run into issues where the dialog cannot be opened again after closing
129
132
  time.sleep(0.05)
130
- _enqueue_message(msg)
133
+ enqueue_message(msg)
131
134
 
132
135
  def open(self) -> None:
133
136
  self._update(True)
@@ -19,10 +19,11 @@ from typing import TYPE_CHECKING, Literal, cast
19
19
 
20
20
  from typing_extensions import Self, TypeAlias
21
21
 
22
- from streamlit.delta_generator import DeltaGenerator, _enqueue_message
22
+ 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
27
 
27
28
  if TYPE_CHECKING:
28
29
  from types import TracebackType
@@ -150,7 +151,7 @@ class StatusContainer(DeltaGenerator):
150
151
  self._current_state = state
151
152
 
152
153
  self._current_proto = msg.delta.add_block
153
- _enqueue_message(msg)
154
+ enqueue_message(msg)
154
155
 
155
156
  def __enter__(self) -> Self: # type: ignore[override]
156
157
  # This is a little dubious: we're returning a different type than
@@ -33,6 +33,7 @@ from streamlit.runtime.metrics_util import gather_metrics
33
33
  from streamlit.runtime.scriptrunner import get_script_run_ctx
34
34
  from streamlit.runtime.state.common import compute_widget_id
35
35
  from streamlit.time_util import time_to_seconds
36
+ from streamlit.type_util import NumpyShape
36
37
 
37
38
  if TYPE_CHECKING:
38
39
  from typing import Any
@@ -41,6 +42,7 @@ if TYPE_CHECKING:
41
42
 
42
43
  from streamlit.delta_generator import DeltaGenerator
43
44
 
45
+
44
46
  MediaData: TypeAlias = Union[
45
47
  str, bytes, io.BytesIO, io.RawIOBase, io.BufferedReader, "npt.NDArray[Any]", None
46
48
  ]
@@ -633,29 +635,29 @@ def _validate_and_normalize(data: npt.NDArray[Any]) -> tuple[bytes, int]:
633
635
  # to st.audio data)
634
636
  import numpy as np
635
637
 
636
- data: npt.NDArray[Any] = np.array(data, dtype=float)
638
+ transformed_data: npt.NDArray[Any] = np.array(data, dtype=float)
637
639
 
638
- if len(data.shape) == 1:
640
+ if len(cast(NumpyShape, transformed_data.shape)) == 1:
639
641
  nchan = 1
640
- elif len(data.shape) == 2:
642
+ elif len(transformed_data.shape) == 2:
641
643
  # In wave files,channels are interleaved. E.g.,
642
644
  # "L1R1L2R2..." for stereo. See
643
645
  # http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
644
646
  # for channel ordering
645
- nchan = data.shape[0]
646
- data = data.T.ravel()
647
+ nchan = transformed_data.shape[0]
648
+ transformed_data = transformed_data.T.ravel()
647
649
  else:
648
650
  raise StreamlitAPIException("Numpy array audio input must be a 1D or 2D array.")
649
651
 
650
- if data.size == 0:
651
- return data.astype(np.int16).tobytes(), nchan
652
+ if transformed_data.size == 0:
653
+ return transformed_data.astype(np.int16).tobytes(), nchan
652
654
 
653
- max_abs_value = np.max(np.abs(data))
655
+ max_abs_value = np.max(np.abs(transformed_data))
654
656
  # 16-bit samples are stored as 2's-complement signed integers,
655
657
  # ranging from -32768 to 32767.
656
658
  # scaled_data is PCM 16 bit numpy array, that's why we multiply [-1, 1] float
657
659
  # values to 32_767 == 2 ** 15 - 1.
658
- np_array = (data / max_abs_value) * 32767
660
+ np_array = (transformed_data / max_abs_value) * 32767
659
661
  scaled_data = np_array.astype(np.int16)
660
662
  return scaled_data.tobytes(), nchan
661
663
 
@@ -16,7 +16,7 @@ from __future__ import annotations
16
16
 
17
17
  from dataclasses import dataclass
18
18
  from textwrap import dedent
19
- from typing import TYPE_CHECKING, Literal, Union, cast
19
+ from typing import TYPE_CHECKING, Any, Literal, Union, cast
20
20
 
21
21
  from typing_extensions import TypeAlias
22
22
 
@@ -36,7 +36,7 @@ if TYPE_CHECKING:
36
36
  from streamlit.delta_generator import DeltaGenerator
37
37
 
38
38
 
39
- Value: TypeAlias = Union["np.integer", "np.floating", float, int, str, None]
39
+ Value: TypeAlias = Union["np.integer[Any]", "np.floating[Any]", float, int, str, None]
40
40
  Delta: TypeAlias = Union[float, int, str, None]
41
41
  DeltaColor: TypeAlias = Literal["normal", "inverse", "off"]
42
42
 
@@ -17,6 +17,7 @@
17
17
  from __future__ import annotations
18
18
 
19
19
  import collections
20
+ import collections.abc
20
21
  import dataclasses
21
22
  import datetime
22
23
  import functools
@@ -31,7 +32,8 @@ import threading
31
32
  import uuid
32
33
  import weakref
33
34
  from enum import Enum
34
- from typing import Any, Callable, Dict, Final, Pattern, Type, Union
35
+ from types import MappingProxyType
36
+ from typing import Any, Callable, Dict, Final, Pattern, Type, Union, cast
35
37
 
36
38
  from typing_extensions import TypeAlias
37
39
 
@@ -405,15 +407,15 @@ class _CacheFuncHasher:
405
407
  elif obj is False:
406
408
  return b"0"
407
409
 
408
- elif dataclasses.is_dataclass(obj):
410
+ elif not isinstance(obj, type) and dataclasses.is_dataclass(obj):
409
411
  return self.to_bytes(dataclasses.asdict(obj))
410
-
411
412
  elif isinstance(obj, Enum):
412
413
  return str(obj).encode()
413
414
 
414
415
  elif type_util.is_type(obj, "pandas.core.series.Series"):
415
416
  import pandas as pd
416
417
 
418
+ obj = cast(pd.Series, obj)
417
419
  self.update(h, obj.size)
418
420
  self.update(h, obj.dtype.name)
419
421
 
@@ -431,6 +433,7 @@ class _CacheFuncHasher:
431
433
  elif type_util.is_type(obj, "pandas.core.frame.DataFrame"):
432
434
  import pandas as pd
433
435
 
436
+ obj = cast(pd.DataFrame, obj)
434
437
  self.update(h, obj.shape)
435
438
 
436
439
  if len(obj) >= _PANDAS_ROWS_LARGE:
@@ -449,6 +452,11 @@ class _CacheFuncHasher:
449
452
  return b"%s" % pickle.dumps(obj, pickle.HIGHEST_PROTOCOL)
450
453
 
451
454
  elif type_util.is_type(obj, "numpy.ndarray"):
455
+ import numpy as np
456
+
457
+ # write cast type as string to make it work with our Python 3.8 tests
458
+ # - can be removed once we sunset support for Python 3.8
459
+ obj = cast("np.ndarray[Any, Any]", obj)
452
460
  self.update(h, obj.shape)
453
461
  self.update(h, str(obj.dtype))
454
462
 
@@ -462,6 +470,9 @@ class _CacheFuncHasher:
462
470
  return h.digest()
463
471
  elif type_util.is_type(obj, "PIL.Image.Image"):
464
472
  import numpy as np
473
+ from PIL.Image import Image
474
+
475
+ obj = cast(Image, obj)
465
476
 
466
477
  # we don't just hash the results of obj.tobytes() because we want to use
467
478
  # the sampling logic for numpy data
@@ -471,8 +482,8 @@ class _CacheFuncHasher:
471
482
  elif inspect.isbuiltin(obj):
472
483
  return bytes(obj.__name__.encode())
473
484
 
474
- elif type_util.is_type(obj, "builtins.mappingproxy") or type_util.is_type(
475
- obj, "builtins.dict_items"
485
+ elif isinstance(obj, MappingProxyType) or isinstance(
486
+ obj, collections.abc.ItemsView
476
487
  ):
477
488
  return self.to_bytes(dict(obj))
478
489
 
@@ -17,6 +17,7 @@ from streamlit.runtime.scriptrunner.script_requests import RerunData
17
17
  from streamlit.runtime.scriptrunner.script_run_context import (
18
18
  ScriptRunContext,
19
19
  add_script_run_ctx,
20
+ enqueue_message,
20
21
  get_script_run_ctx,
21
22
  )
22
23
  from streamlit.runtime.scriptrunner.script_runner import ScriptRunner, ScriptRunnerEvent
@@ -26,6 +27,7 @@ __all__ = [
26
27
  "ScriptRunContext",
27
28
  "add_script_run_ctx",
28
29
  "get_script_run_ctx",
30
+ "enqueue_message",
29
31
  "RerunException",
30
32
  "ScriptRunner",
31
33
  "ScriptRunnerEvent",
@@ -26,7 +26,7 @@ if TYPE_CHECKING:
26
26
 
27
27
 
28
28
  def exec_func_with_error_handling(
29
- func: Callable[[], None], ctx: ScriptRunContext
29
+ func: Callable[[], Any], ctx: ScriptRunContext
30
30
  ) -> tuple[
31
31
  Any | None,
32
32
  bool,
@@ -22,8 +22,7 @@ from urllib import parse
22
22
 
23
23
  from typing_extensions import TypeAlias
24
24
 
25
- from streamlit import runtime
26
- from streamlit.errors import StreamlitAPIException
25
+ from streamlit.errors import NoSessionContext, StreamlitAPIException
27
26
  from streamlit.logger import get_logger
28
27
 
29
28
  if TYPE_CHECKING:
@@ -224,15 +223,28 @@ def get_script_run_ctx(suppress_warning: bool = False) -> ScriptRunContext | Non
224
223
  """
225
224
  thread = threading.current_thread()
226
225
  ctx: ScriptRunContext | None = getattr(thread, SCRIPT_RUN_CONTEXT_ATTR_NAME, None)
227
- if ctx is None and runtime.exists() and not suppress_warning:
226
+ if ctx is None and not suppress_warning:
228
227
  # Only warn about a missing ScriptRunContext if suppress_warning is False, and
229
228
  # we were started via `streamlit run`. Otherwise, the user is likely running a
230
229
  # script "bare", and doesn't need to be warned about streamlit
231
230
  # bits that are irrelevant when not connected to a session.
232
- _LOGGER.warning("Thread '%s': missing ScriptRunContext", thread.name)
231
+ _LOGGER.warning(
232
+ "Thread '%s': missing ScriptRunContext! This warning can be ignored when "
233
+ "running in bare mode.",
234
+ thread.name,
235
+ )
233
236
 
234
237
  return ctx
235
238
 
236
239
 
237
- # Needed to avoid circular dependencies while running tests.
238
- import streamlit # noqa: E402, F401
240
+ def enqueue_message(msg: ForwardMsg) -> None:
241
+ """Enqueues a ForwardMsg proto to send to the app."""
242
+ ctx = get_script_run_ctx()
243
+
244
+ if ctx is None:
245
+ raise NoSessionContext()
246
+
247
+ if ctx.current_fragment_id and msg.WhichOneof("type") == "delta":
248
+ msg.delta.fragment_id = ctx.current_fragment_id
249
+
250
+ ctx.enqueue(msg)
streamlit/source_util.py CHANGED
@@ -17,7 +17,7 @@ from __future__ import annotations
17
17
  import re
18
18
  import threading
19
19
  from pathlib import Path
20
- from typing import Any, Callable, Final, TypedDict, cast
20
+ from typing import Callable, Final, TypedDict
21
21
 
22
22
  from blinker import Signal
23
23
  from typing_extensions import NotRequired, TypeAlias
@@ -88,15 +88,10 @@ def page_icon_and_name(script_path: Path) -> tuple[str, str]:
88
88
  URL-encode them. To solve this, we only swap the underscores for spaces
89
89
  right before we render page names.
90
90
  """
91
- extraction = re.search(PAGE_FILENAME_REGEX, script_path.name)
91
+ extraction: re.Match[str] | None = re.search(PAGE_FILENAME_REGEX, script_path.name)
92
92
  if extraction is None:
93
93
  return "", ""
94
94
 
95
- # This cast to Any+type annotation weirdness is done because
96
- # cast(re.Match[str], ...) explodes at runtime since Python interprets it
97
- # as an attempt to index into re.Match instead of as a type annotation.
98
- extraction: re.Match[str] = cast(Any, extraction)
99
-
100
95
  icon_and_name = re.sub(
101
96
  r"[_ ]+", "_", extraction.group(2)
102
97
  ).strip() or extraction.group(1)
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "files": {
3
3
  "main.css": "./static/css/main.554f96d9.css",
4
- "main.js": "./static/js/main.80efcd23.js",
4
+ "main.js": "./static/js/main.d1c1e1f9.js",
5
5
  "static/js/9336.3e046ad7.chunk.js": "./static/js/9336.3e046ad7.chunk.js",
6
6
  "static/js/9330.2b4c99e0.chunk.js": "./static/js/9330.2b4c99e0.chunk.js",
7
7
  "static/js/2736.7d516fcc.chunk.js": "./static/js/2736.7d516fcc.chunk.js",
@@ -153,6 +153,6 @@
153
153
  },
154
154
  "entrypoints": [
155
155
  "static/css/main.554f96d9.css",
156
- "static/js/main.80efcd23.js"
156
+ "static/js/main.d1c1e1f9.js"
157
157
  ]
158
158
  }
@@ -1 +1 @@
1
- <!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><link rel="shortcut icon" href="./favicon.png"/><link rel="preload" href="./static/media/SourceSansPro-Regular.0d69e5ff5e92ac64a0c9.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="./static/media/SourceSansPro-SemiBold.abed79cd0df1827e18cf.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="./static/media/SourceSansPro-Bold.118dea98980e20a81ced.woff2" as="font" type="font/woff2" crossorigin><title>Streamlit</title><script>window.prerenderReady=!1</script><script defer="defer" src="./static/js/main.80efcd23.js"></script><link href="./static/css/main.554f96d9.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
1
+ <!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><link rel="shortcut icon" href="./favicon.png"/><link rel="preload" href="./static/media/SourceSansPro-Regular.0d69e5ff5e92ac64a0c9.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="./static/media/SourceSansPro-SemiBold.abed79cd0df1827e18cf.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="./static/media/SourceSansPro-Bold.118dea98980e20a81ced.woff2" as="font" type="font/woff2" crossorigin><title>Streamlit</title><script>window.prerenderReady=!1</script><script defer="defer" src="./static/js/main.d1c1e1f9.js"></script><link href="./static/css/main.554f96d9.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>