streamlit-nightly 1.31.2.dev20240213__py2.py3-none-any.whl → 1.31.2.dev20240214__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/case_converters.py +9 -4
- streamlit/cli_util.py +2 -0
- streamlit/code_util.py +5 -2
- streamlit/color_util.py +2 -0
- streamlit/column_config.py +2 -0
- streamlit/commands/execution_control.py +4 -2
- streamlit/commands/experimental_query_params.py +7 -4
- streamlit/commands/page_config.py +11 -9
- streamlit/components/v1/components.py +23 -16
- streamlit/config.py +3 -5
- streamlit/config_option.py +12 -11
- streamlit/connections/base_connection.py +4 -2
- streamlit/connections/snowflake_connection.py +4 -4
- streamlit/connections/snowpark_connection.py +3 -3
- streamlit/connections/sql_connection.py +6 -6
- streamlit/connections/util.py +8 -5
- streamlit/constants.py +2 -0
- streamlit/cursor.py +16 -14
- streamlit/delta_generator.py +10 -13
- streamlit/deprecation_util.py +4 -3
- streamlit/echo.py +5 -3
- streamlit/elements/alert.py +16 -14
- streamlit/elements/altair_utils.py +8 -6
- streamlit/elements/arrow.py +4 -4
- streamlit/elements/arrow_altair.py +24 -34
- streamlit/elements/arrow_vega_lite.py +9 -14
- streamlit/elements/balloons.py +4 -2
- streamlit/elements/bokeh_chart.py +7 -7
- streamlit/elements/code.py +6 -4
- streamlit/elements/deck_gl_json_chart.py +8 -8
- streamlit/elements/doc_string.py +5 -9
- streamlit/elements/empty.py +4 -2
- streamlit/elements/exception.py +10 -10
- streamlit/elements/form.py +1 -3
- streamlit/elements/graphviz_chart.py +5 -6
- streamlit/elements/heading.py +16 -14
- streamlit/elements/iframe.py +14 -12
- streamlit/elements/image.py +8 -8
- streamlit/elements/json.py +6 -4
- streamlit/elements/layouts.py +12 -10
- streamlit/elements/lib/column_config_utils.py +2 -2
- streamlit/elements/lib/column_types.py +23 -23
- streamlit/elements/lib/dicttools.py +10 -6
- streamlit/elements/lib/mutable_status_container.py +7 -7
- streamlit/elements/lib/pandas_styler_utils.py +6 -6
- streamlit/elements/lib/streamlit_plotly_theme.py +2 -0
- streamlit/elements/map.py +11 -22
- streamlit/elements/markdown.py +16 -14
- streamlit/elements/media.py +16 -16
- streamlit/elements/metric.py +9 -7
- streamlit/elements/plotly_chart.py +5 -5
- streamlit/elements/progress.py +6 -6
- streamlit/elements/pyplot.py +10 -13
- streamlit/elements/snow.py +4 -2
- streamlit/elements/spinner.py +2 -0
- streamlit/elements/text.py +7 -5
- streamlit/elements/toast.py +6 -4
- streamlit/elements/utils.py +15 -28
- streamlit/elements/widgets/button.py +39 -39
- streamlit/elements/widgets/camera_input.py +21 -17
- streamlit/elements/widgets/chat.py +6 -7
- streamlit/elements/widgets/checkbox.py +21 -19
- streamlit/elements/widgets/color_picker.py +18 -16
- streamlit/elements/widgets/data_editor.py +7 -7
- streamlit/elements/widgets/file_uploader.py +59 -55
- streamlit/elements/widgets/multiselect.py +33 -42
- streamlit/elements/widgets/number_input.py +10 -5
- streamlit/elements/widgets/radio.py +1 -1
- streamlit/elements/widgets/select_slider.py +25 -34
- streamlit/elements/widgets/selectbox.py +1 -1
- streamlit/elements/widgets/slider.py +28 -36
- streamlit/elements/widgets/text_widgets.py +6 -6
- streamlit/elements/widgets/time_widgets.py +13 -13
- streamlit/elements/write.py +8 -19
- streamlit/env_util.py +5 -3
- streamlit/error_util.py +7 -3
- streamlit/errors.py +3 -1
- streamlit/external/langchain/streamlit_callback_handler.py +26 -24
- streamlit/file_util.py +18 -14
- streamlit/folder_black_list.py +3 -1
- streamlit/git_util.py +5 -3
- streamlit/js_number.py +10 -13
- streamlit/logger.py +5 -5
- streamlit/net_util.py +14 -11
- streamlit/platform.py +2 -0
- streamlit/runtime/__init__.py +2 -0
- streamlit/runtime/app_session.py +42 -42
- streamlit/runtime/caching/__init__.py +4 -4
- streamlit/runtime/caching/cache_data_api.py +3 -3
- streamlit/runtime/caching/cache_errors.py +5 -3
- streamlit/runtime/caching/cache_type.py +2 -0
- streamlit/runtime/caching/cache_utils.py +2 -4
- streamlit/runtime/caching/cached_message_replay.py +12 -5
- streamlit/runtime/caching/storage/cache_storage_protocol.py +1 -2
- streamlit/runtime/caching/storage/local_disk_cache_storage.py +6 -5
- streamlit/runtime/connection_factory.py +8 -8
- streamlit/runtime/forward_msg_cache.py +20 -18
- streamlit/runtime/forward_msg_queue.py +8 -9
- streamlit/runtime/legacy_caching/caching.py +32 -42
- streamlit/runtime/media_file_manager.py +16 -14
- streamlit/runtime/media_file_storage.py +8 -8
- streamlit/runtime/memory_media_file_storage.py +12 -14
- streamlit/runtime/memory_session_storage.py +4 -3
- streamlit/runtime/memory_uploaded_file_manager.py +9 -10
- streamlit/runtime/metrics_util.py +20 -20
- streamlit/runtime/runtime.py +25 -27
- streamlit/runtime/runtime_util.py +5 -3
- streamlit/runtime/script_data.py +2 -0
- streamlit/runtime/scriptrunner/magic.py +17 -11
- streamlit/runtime/scriptrunner/magic_funcs.py +2 -0
- streamlit/runtime/scriptrunner/script_requests.py +6 -4
- streamlit/runtime/scriptrunner/script_run_context.py +17 -17
- streamlit/runtime/scriptrunner/script_runner.py +7 -5
- streamlit/runtime/secrets.py +4 -6
- streamlit/runtime/session_manager.py +14 -14
- streamlit/runtime/state/common.py +5 -4
- streamlit/runtime/state/query_params.py +8 -6
- streamlit/runtime/state/query_params_proxy.py +7 -5
- streamlit/runtime/state/safe_session_state.py +7 -5
- streamlit/runtime/state/session_state.py +3 -4
- streamlit/runtime/state/session_state_proxy.py +5 -5
- streamlit/runtime/state/widgets.py +20 -18
- streamlit/runtime/uploaded_file_manager.py +6 -5
- streamlit/runtime/websocket_session_manager.py +14 -14
- streamlit/source_util.py +13 -11
- streamlit/string_util.py +13 -9
- streamlit/temporary_directory.py +3 -1
- streamlit/testing/v1/element_tree.py +1 -2
- streamlit/type_util.py +21 -25
- streamlit/url_util.py +6 -4
- streamlit/user_info.py +8 -6
- streamlit/util.py +23 -37
- streamlit/watcher/event_based_path_watcher.py +10 -10
- streamlit/watcher/local_sources_watcher.py +15 -13
- streamlit/watcher/path_watcher.py +0 -3
- streamlit/watcher/polling_path_watcher.py +9 -8
- streamlit/watcher/util.py +3 -2
- streamlit/web/cache_storage_manager_config.py +2 -0
- streamlit/web/server/app_static_file_handler.py +6 -5
- streamlit/web/server/browser_websocket_handler.py +10 -8
- streamlit/web/server/component_request_handler.py +7 -4
- streamlit/web/server/media_file_handler.py +5 -4
- streamlit/web/server/routes.py +6 -3
- streamlit/web/server/server.py +31 -31
- streamlit/web/server/server_util.py +4 -2
- streamlit/web/server/upload_file_request_handler.py +7 -8
- streamlit/web/server/websocket_headers.py +2 -2
- {streamlit_nightly-1.31.2.dev20240213.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/METADATA +1 -1
- {streamlit_nightly-1.31.2.dev20240213.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/RECORD +153 -153
- {streamlit_nightly-1.31.2.dev20240213.data → streamlit_nightly-1.31.2.dev20240214.data}/scripts/streamlit.cmd +0 -0
- {streamlit_nightly-1.31.2.dev20240213.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/WHEEL +0 -0
- {streamlit_nightly-1.31.2.dev20240213.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/entry_points.txt +0 -0
- {streamlit_nightly-1.31.2.dev20240213.dist-info → streamlit_nightly-1.31.2.dev20240214.dist-info}/top_level.txt +0 -0
streamlit/source_util.py
CHANGED
@@ -12,10 +12,12 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
from __future__ import annotations
|
16
|
+
|
15
17
|
import re
|
16
18
|
import threading
|
17
19
|
from pathlib import Path
|
18
|
-
from typing import Any, Callable,
|
20
|
+
from typing import Any, Callable, Final, cast
|
19
21
|
|
20
22
|
from blinker import Signal
|
21
23
|
|
@@ -23,10 +25,10 @@ from streamlit.logger import get_logger
|
|
23
25
|
from streamlit.string_util import extract_leading_emoji
|
24
26
|
from streamlit.util import calc_md5
|
25
27
|
|
26
|
-
|
28
|
+
_LOGGER: Final = get_logger(__name__)
|
27
29
|
|
28
30
|
|
29
|
-
def open_python_file(filename):
|
31
|
+
def open_python_file(filename: str):
|
30
32
|
"""Open a read-only Python file taking proper care of its encoding.
|
31
33
|
|
32
34
|
In Python 3, we would like all files to be opened with utf-8 encoding.
|
@@ -41,13 +43,13 @@ def open_python_file(filename):
|
|
41
43
|
# found, opens as utf-8.
|
42
44
|
return tokenize.open(filename)
|
43
45
|
else:
|
44
|
-
return open(filename,
|
46
|
+
return open(filename, encoding="utf-8")
|
45
47
|
|
46
48
|
|
47
49
|
PAGE_FILENAME_REGEX = re.compile(r"([0-9]*)[_ -]*(.*)\.py")
|
48
50
|
|
49
51
|
|
50
|
-
def page_sort_key(script_path: Path) ->
|
52
|
+
def page_sort_key(script_path: Path) -> tuple[float, str]:
|
51
53
|
matches = re.findall(PAGE_FILENAME_REGEX, script_path.name)
|
52
54
|
|
53
55
|
# Failing this assert should only be possible if script_path isn't a Python
|
@@ -63,7 +65,7 @@ def page_sort_key(script_path: Path) -> Tuple[float, str]:
|
|
63
65
|
return (float(number), label)
|
64
66
|
|
65
67
|
|
66
|
-
def page_icon_and_name(script_path: Path) ->
|
68
|
+
def page_icon_and_name(script_path: Path) -> tuple[str, str]:
|
67
69
|
"""Compute the icon and name of a page from its script path.
|
68
70
|
|
69
71
|
This is *almost* the page name displayed in the nav UI, but it has
|
@@ -89,21 +91,21 @@ def page_icon_and_name(script_path: Path) -> Tuple[str, str]:
|
|
89
91
|
|
90
92
|
|
91
93
|
_pages_cache_lock = threading.RLock()
|
92
|
-
_cached_pages:
|
94
|
+
_cached_pages: dict[str, dict[str, str]] | None = None
|
93
95
|
_on_pages_changed = Signal(doc="Emitted when the pages directory is changed")
|
94
96
|
|
95
97
|
|
96
|
-
def invalidate_pages_cache():
|
98
|
+
def invalidate_pages_cache() -> None:
|
97
99
|
global _cached_pages
|
98
100
|
|
99
|
-
|
101
|
+
_LOGGER.debug("Pages directory changed")
|
100
102
|
with _pages_cache_lock:
|
101
103
|
_cached_pages = None
|
102
104
|
|
103
105
|
_on_pages_changed.send()
|
104
106
|
|
105
107
|
|
106
|
-
def get_pages(main_script_path_str: str) ->
|
108
|
+
def get_pages(main_script_path_str: str) -> dict[str, dict[str, str]]:
|
107
109
|
global _cached_pages
|
108
110
|
|
109
111
|
# Avoid taking the lock if the pages cache hasn't been invalidated.
|
@@ -162,7 +164,7 @@ def get_pages(main_script_path_str: str) -> Dict[str, Dict[str, str]]:
|
|
162
164
|
|
163
165
|
def register_pages_changed_callback(
|
164
166
|
callback: Callable[[str], None],
|
165
|
-
):
|
167
|
+
) -> Callable[[], None]:
|
166
168
|
def disconnect():
|
167
169
|
_on_pages_changed.disconnect(callback)
|
168
170
|
|
streamlit/string_util.py
CHANGED
@@ -16,14 +16,14 @@ from __future__ import annotations
|
|
16
16
|
|
17
17
|
import re
|
18
18
|
import textwrap
|
19
|
-
from typing import TYPE_CHECKING, Any,
|
19
|
+
from typing import TYPE_CHECKING, Any, Final, cast
|
20
20
|
|
21
21
|
from streamlit.errors import StreamlitAPIException
|
22
22
|
|
23
23
|
if TYPE_CHECKING:
|
24
24
|
from streamlit.type_util import SupportsStr
|
25
25
|
|
26
|
-
_ALPHANUMERIC_CHAR_REGEX = re.compile(r"^[a-zA-Z0-9_&\-\. ]+$")
|
26
|
+
_ALPHANUMERIC_CHAR_REGEX: Final = re.compile(r"^[a-zA-Z0-9_&\-\. ]+$")
|
27
27
|
|
28
28
|
|
29
29
|
def decode_ascii(string: bytes) -> str:
|
@@ -31,7 +31,7 @@ def decode_ascii(string: bytes) -> str:
|
|
31
31
|
return string.decode("ascii")
|
32
32
|
|
33
33
|
|
34
|
-
def clean_text(text:
|
34
|
+
def clean_text(text: SupportsStr) -> str:
|
35
35
|
"""Convert an object to text, dedent it, and strip whitespace."""
|
36
36
|
return textwrap.dedent(str(text)).strip()
|
37
37
|
|
@@ -67,7 +67,7 @@ def validate_emoji(maybe_emoji: str | None) -> str:
|
|
67
67
|
)
|
68
68
|
|
69
69
|
|
70
|
-
def extract_leading_emoji(text: str) ->
|
70
|
+
def extract_leading_emoji(text: str) -> tuple[str, str]:
|
71
71
|
"""Return a tuple containing the first emoji found in the given string and
|
72
72
|
the rest of the string (minus an optional separator between the two).
|
73
73
|
"""
|
@@ -115,7 +115,9 @@ def escape_markdown(raw_string: str) -> str:
|
|
115
115
|
return result
|
116
116
|
|
117
117
|
|
118
|
-
TEXTCHARS = bytearray(
|
118
|
+
TEXTCHARS: Final = bytearray(
|
119
|
+
{7, 8, 9, 10, 12, 13, 27} | set(range(0x20, 0x100)) - {0x7F}
|
120
|
+
)
|
119
121
|
|
120
122
|
|
121
123
|
def is_binary_string(inp: bytes) -> bool:
|
@@ -126,18 +128,20 @@ def is_binary_string(inp: bytes) -> bool:
|
|
126
128
|
|
127
129
|
def simplify_number(num: int) -> str:
|
128
130
|
"""Simplifies number into Human readable format, returns str"""
|
129
|
-
num_converted = float("{:.2g}"
|
131
|
+
num_converted = float(f"{num:.2g}")
|
130
132
|
magnitude = 0
|
131
133
|
while abs(num_converted) >= 1000:
|
132
134
|
magnitude += 1
|
133
135
|
num_converted /= 1000.0
|
134
136
|
return "{}{}".format(
|
135
|
-
"{:f}".
|
137
|
+
f"{num_converted:f}".rstrip("0").rstrip("."),
|
136
138
|
["", "k", "m", "b", "t"][magnitude],
|
137
139
|
)
|
138
140
|
|
139
141
|
|
140
|
-
_OBJ_MEM_ADDRESS = re.compile(
|
142
|
+
_OBJ_MEM_ADDRESS: Final = re.compile(
|
143
|
+
r"^\<[a-zA-Z_]+[a-zA-Z0-9<>._ ]* at 0x[0-9a-f]+\>$"
|
144
|
+
)
|
141
145
|
|
142
146
|
|
143
147
|
def is_mem_address_str(string):
|
@@ -148,7 +152,7 @@ def is_mem_address_str(string):
|
|
148
152
|
return False
|
149
153
|
|
150
154
|
|
151
|
-
_RE_CONTAINS_HTML = re.compile(r"(?:</[^<]+>)|(?:<[^<]+/>)")
|
155
|
+
_RE_CONTAINS_HTML: Final = re.compile(r"(?:</[^<]+>)|(?:<[^<]+/>)")
|
152
156
|
|
153
157
|
|
154
158
|
def probably_contains_html_tags(s: str) -> bool:
|
streamlit/temporary_directory.py
CHANGED
@@ -12,6 +12,8 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
from __future__ import annotations
|
16
|
+
|
15
17
|
import shutil
|
16
18
|
import tempfile
|
17
19
|
|
@@ -21,7 +23,7 @@ from streamlit import util
|
|
21
23
|
# tempfile.mkdtemp
|
22
24
|
|
23
25
|
|
24
|
-
class TemporaryDirectory
|
26
|
+
class TemporaryDirectory:
|
25
27
|
"""Temporary directory context manager.
|
26
28
|
|
27
29
|
Creates a temporary directory that exists within the context manager scope.
|
@@ -1383,8 +1383,7 @@ class Block:
|
|
1383
1383
|
def __iter__(self):
|
1384
1384
|
yield self
|
1385
1385
|
for child_idx in self.children:
|
1386
|
-
|
1387
|
-
yield c
|
1386
|
+
yield from self.children[child_idx]
|
1388
1387
|
|
1389
1388
|
def __getitem__(self, k: int) -> Node:
|
1390
1389
|
return self.children[k]
|
streamlit/type_util.py
CHANGED
@@ -25,17 +25,13 @@ from enum import Enum, EnumMeta, auto
|
|
25
25
|
from typing import (
|
26
26
|
TYPE_CHECKING,
|
27
27
|
Any,
|
28
|
-
Dict,
|
29
28
|
Final,
|
30
29
|
Iterable,
|
31
|
-
List,
|
32
30
|
Literal,
|
33
31
|
NamedTuple,
|
34
32
|
Protocol,
|
35
33
|
Sequence,
|
36
|
-
Set,
|
37
34
|
Tuple,
|
38
|
-
Type,
|
39
35
|
TypeVar,
|
40
36
|
Union,
|
41
37
|
cast,
|
@@ -172,11 +168,11 @@ def is_type(
|
|
172
168
|
|
173
169
|
|
174
170
|
@overload
|
175
|
-
def is_type(obj: object, fqn_type_pattern:
|
171
|
+
def is_type(obj: object, fqn_type_pattern: str | re.Pattern[str]) -> bool:
|
176
172
|
...
|
177
173
|
|
178
174
|
|
179
|
-
def is_type(obj: object, fqn_type_pattern:
|
175
|
+
def is_type(obj: object, fqn_type_pattern: str | re.Pattern[str]) -> bool:
|
180
176
|
"""Check type without importing expensive modules.
|
181
177
|
|
182
178
|
Parameters
|
@@ -406,7 +402,7 @@ def is_list_of_scalars(data: Iterable[Any]) -> bool:
|
|
406
402
|
return infer_dtype(data, skipna=True) not in ["mixed", "unknown-array"]
|
407
403
|
|
408
404
|
|
409
|
-
def is_plotly_chart(obj: object) -> TypeGuard[
|
405
|
+
def is_plotly_chart(obj: object) -> TypeGuard[Figure | list[Any] | dict[str, Any]]:
|
410
406
|
"""True if input looks like a Plotly chart."""
|
411
407
|
return (
|
412
408
|
is_type(obj, "plotly.graph_objs._figure.Figure")
|
@@ -417,7 +413,7 @@ def is_plotly_chart(obj: object) -> TypeGuard[Union[Figure, list[Any], dict[str,
|
|
417
413
|
|
418
414
|
def is_graphviz_chart(
|
419
415
|
obj: object,
|
420
|
-
) -> TypeGuard[
|
416
|
+
) -> TypeGuard[graphviz.Graph | graphviz.Digraph]:
|
421
417
|
"""True if input looks like a GraphViz chart."""
|
422
418
|
return (
|
423
419
|
# GraphViz < 0.18
|
@@ -478,7 +474,7 @@ def is_namedtuple(x: object) -> TypeGuard[NamedTuple]:
|
|
478
474
|
return all(type(n).__name__ == "str" for n in f)
|
479
475
|
|
480
476
|
|
481
|
-
def is_pandas_styler(obj: object) -> TypeGuard[
|
477
|
+
def is_pandas_styler(obj: object) -> TypeGuard[Styler]:
|
482
478
|
return is_type(obj, _PANDAS_STYLER_TYPE_STR)
|
483
479
|
|
484
480
|
|
@@ -523,7 +519,7 @@ def convert_anything_to_df(
|
|
523
519
|
max_unevaluated_rows: int = MAX_UNEVALUATED_DF_ROWS,
|
524
520
|
ensure_copy: bool = False,
|
525
521
|
allow_styler: bool = False,
|
526
|
-
) ->
|
522
|
+
) -> DataFrame | Styler:
|
527
523
|
...
|
528
524
|
|
529
525
|
|
@@ -532,7 +528,7 @@ def convert_anything_to_df(
|
|
532
528
|
max_unevaluated_rows: int = MAX_UNEVALUATED_DF_ROWS,
|
533
529
|
ensure_copy: bool = False,
|
534
530
|
allow_styler: bool = False,
|
535
|
-
) ->
|
531
|
+
) -> DataFrame | Styler:
|
536
532
|
"""Try to convert different formats to a Pandas Dataframe.
|
537
533
|
|
538
534
|
Parameters
|
@@ -634,7 +630,7 @@ def ensure_iterable(obj: OptionSequence[V_co]) -> Iterable[Any]:
|
|
634
630
|
...
|
635
631
|
|
636
632
|
|
637
|
-
def ensure_iterable(obj:
|
633
|
+
def ensure_iterable(obj: OptionSequence[V_co] | Iterable[V_co]) -> Iterable[Any]:
|
638
634
|
"""Try to convert different formats to something iterable. Most inputs
|
639
635
|
are assumed to be iterable, but if we have a DataFrame, we can just
|
640
636
|
select the first column to iterate over. If the input is not iterable,
|
@@ -850,7 +846,7 @@ def pyarrow_table_to_bytes(table: pa.Table) -> bytes:
|
|
850
846
|
return cast(bytes, sink.getvalue().to_pybytes())
|
851
847
|
|
852
848
|
|
853
|
-
def is_colum_type_arrow_incompatible(column:
|
849
|
+
def is_colum_type_arrow_incompatible(column: Series[Any] | Index) -> bool:
|
854
850
|
"""Return True if the column type is known to cause issues during Arrow conversion."""
|
855
851
|
from pandas.api.types import infer_dtype, is_dict_like, is_list_like
|
856
852
|
|
@@ -896,7 +892,7 @@ def is_colum_type_arrow_incompatible(column: Union[Series[Any], Index]) -> bool:
|
|
896
892
|
|
897
893
|
|
898
894
|
def fix_arrow_incompatible_column_types(
|
899
|
-
df: DataFrame, selected_columns:
|
895
|
+
df: DataFrame, selected_columns: list[str] | None = None
|
900
896
|
) -> DataFrame:
|
901
897
|
"""Fix column types that are not supported by Arrow table.
|
902
898
|
|
@@ -1075,16 +1071,16 @@ def _unify_missing_values(df: DataFrame) -> DataFrame:
|
|
1075
1071
|
|
1076
1072
|
def convert_df_to_data_format(
|
1077
1073
|
df: DataFrame, data_format: DataFormat
|
1078
|
-
) ->
|
1079
|
-
DataFrame
|
1080
|
-
Series[Any]
|
1081
|
-
pa.Table
|
1082
|
-
np.ndarray[Any, np.dtype[Any]]
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1074
|
+
) -> (
|
1075
|
+
DataFrame
|
1076
|
+
| Series[Any]
|
1077
|
+
| pa.Table
|
1078
|
+
| np.ndarray[Any, np.dtype[Any]]
|
1079
|
+
| tuple[Any]
|
1080
|
+
| list[Any]
|
1081
|
+
| set[Any]
|
1082
|
+
| dict[str, Any]
|
1083
|
+
):
|
1088
1084
|
"""Convert a dataframe to the specified data format.
|
1089
1085
|
|
1090
1086
|
Parameters
|
@@ -1279,7 +1275,7 @@ E2 = TypeVar("E2", bound=Enum)
|
|
1279
1275
|
ALLOWED_ENUM_COERCION_CONFIG_SETTINGS = ("off", "nameOnly", "nameAndValue")
|
1280
1276
|
|
1281
1277
|
|
1282
|
-
def coerce_enum(from_enum_value: E1, to_enum_class:
|
1278
|
+
def coerce_enum(from_enum_value: E1, to_enum_class: type[E2]) -> E1 | E2:
|
1283
1279
|
"""Attempt to coerce an Enum value to another EnumMeta.
|
1284
1280
|
|
1285
1281
|
An Enum value of EnumMeta E1 is considered coercable to EnumType E2
|
streamlit/url_util.py
CHANGED
@@ -12,8 +12,10 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
from __future__ import annotations
|
16
|
+
|
15
17
|
import re
|
16
|
-
from typing import
|
18
|
+
from typing import Final, Literal
|
17
19
|
from urllib.parse import urlparse
|
18
20
|
|
19
21
|
from typing_extensions import TypeAlias
|
@@ -22,7 +24,7 @@ UrlSchema: TypeAlias = Literal["http", "https", "mailto", "data"]
|
|
22
24
|
|
23
25
|
|
24
26
|
# Regular expression for process_gitblob_url
|
25
|
-
_GITBLOB_RE = re.compile(
|
27
|
+
_GITBLOB_RE: Final = re.compile(
|
26
28
|
r"(?P<base>https:\/\/?(gist\.)?github.com\/)"
|
27
29
|
r"(?P<account>([\w\.]+\/){1,2})"
|
28
30
|
r"(?P<blob_or_raw>(blob|raw))?"
|
@@ -55,7 +57,7 @@ def process_gitblob_url(url: str) -> str:
|
|
55
57
|
return url
|
56
58
|
|
57
59
|
|
58
|
-
def get_hostname(url: str) ->
|
60
|
+
def get_hostname(url: str) -> str | None:
|
59
61
|
"""Return the hostname of a URL (with or without protocol)."""
|
60
62
|
# Just so urllib can parse the URL, make sure there's a protocol.
|
61
63
|
# (The actual protocol doesn't matter to us)
|
@@ -68,7 +70,7 @@ def get_hostname(url: str) -> Optional[str]:
|
|
68
70
|
|
69
71
|
def is_url(
|
70
72
|
url: str,
|
71
|
-
allowed_schemas:
|
73
|
+
allowed_schemas: tuple[UrlSchema, ...] = ("http", "https"),
|
72
74
|
) -> bool:
|
73
75
|
"""Check if a string looks like an URL.
|
74
76
|
|
streamlit/user_info.py
CHANGED
@@ -12,7 +12,9 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
from
|
15
|
+
from __future__ import annotations
|
16
|
+
|
17
|
+
from typing import Iterator, Mapping, NoReturn, Union
|
16
18
|
|
17
19
|
from streamlit.errors import StreamlitAPIException
|
18
20
|
from streamlit.runtime.scriptrunner import get_script_run_ctx as _get_script_run_ctx
|
@@ -29,7 +31,7 @@ def _get_user_info() -> UserInfo:
|
|
29
31
|
|
30
32
|
# Class attributes are listed as "Parameters" in the docstring as a workaround
|
31
33
|
# for the docstring parser for docs.strreamlit.io
|
32
|
-
class UserInfoProxy(Mapping[str,
|
34
|
+
class UserInfoProxy(Mapping[str, Union[str, None]]):
|
33
35
|
"""
|
34
36
|
A read-only, dict-like object for accessing information about current user.
|
35
37
|
|
@@ -58,19 +60,19 @@ class UserInfoProxy(Mapping[str, Optional[str]]):
|
|
58
60
|
|
59
61
|
"""
|
60
62
|
|
61
|
-
def __getitem__(self, key: str) ->
|
63
|
+
def __getitem__(self, key: str) -> str | None:
|
62
64
|
return _get_user_info()[key]
|
63
65
|
|
64
|
-
def __getattr__(self, key: str) ->
|
66
|
+
def __getattr__(self, key: str) -> str | None:
|
65
67
|
try:
|
66
68
|
return _get_user_info()[key]
|
67
69
|
except KeyError:
|
68
70
|
raise AttributeError
|
69
71
|
|
70
|
-
def __setattr__(self, name: str, value:
|
72
|
+
def __setattr__(self, name: str, value: str | None) -> NoReturn:
|
71
73
|
raise StreamlitAPIException("st.experimental_user cannot be modified")
|
72
74
|
|
73
|
-
def __setitem__(self, name: str, value:
|
75
|
+
def __setitem__(self, name: str, value: str | None) -> NoReturn:
|
74
76
|
raise StreamlitAPIException("st.experimental_user cannot be modified")
|
75
77
|
|
76
78
|
def __iter__(self) -> Iterator[str]:
|
streamlit/util.py
CHANGED
@@ -23,21 +23,9 @@ import hashlib
|
|
23
23
|
import os
|
24
24
|
import subprocess
|
25
25
|
import sys
|
26
|
-
from typing import
|
27
|
-
Any,
|
28
|
-
Dict,
|
29
|
-
Generic,
|
30
|
-
Iterable,
|
31
|
-
List,
|
32
|
-
Mapping,
|
33
|
-
Optional,
|
34
|
-
Set,
|
35
|
-
TypeVar,
|
36
|
-
Union,
|
37
|
-
)
|
26
|
+
from typing import Any, Callable, Final, Generic, Iterable, Mapping, TypeVar
|
38
27
|
|
39
28
|
from cachetools import TTLCache
|
40
|
-
from typing_extensions import Final
|
41
29
|
|
42
30
|
from streamlit import env_util
|
43
31
|
|
@@ -47,14 +35,14 @@ FLOAT_EQUALITY_EPSILON: Final[float] = 0.000000000005
|
|
47
35
|
|
48
36
|
# Due to security issue in md5 and sha1, usedforsecurity
|
49
37
|
# argument is added to hashlib for python versions higher than 3.8
|
50
|
-
HASHLIB_KWARGS:
|
38
|
+
HASHLIB_KWARGS: dict[str, Any] = (
|
51
39
|
{"usedforsecurity": False} if sys.version_info >= (3, 9) else {}
|
52
40
|
)
|
53
41
|
|
54
42
|
|
55
|
-
def memoize(func):
|
43
|
+
def memoize(func: Callable[..., Any]) -> Callable[..., Any]:
|
56
44
|
"""Decorator to memoize the result of a no-args func."""
|
57
|
-
result:
|
45
|
+
result: list[Any] = []
|
58
46
|
|
59
47
|
@functools.wraps(func)
|
60
48
|
def wrapped_func():
|
@@ -65,7 +53,7 @@ def memoize(func):
|
|
65
53
|
return wrapped_func
|
66
54
|
|
67
55
|
|
68
|
-
def open_browser(url):
|
56
|
+
def open_browser(url: str) -> None:
|
69
57
|
"""Open a web browser pointing to a given URL.
|
70
58
|
|
71
59
|
We use this function instead of Python's `webbrowser` module because this
|
@@ -107,13 +95,13 @@ def open_browser(url):
|
|
107
95
|
raise Error('Cannot open browser in platform "%s"' % platform.system())
|
108
96
|
|
109
97
|
|
110
|
-
def _open_browser_with_webbrowser(url):
|
98
|
+
def _open_browser_with_webbrowser(url: str) -> None:
|
111
99
|
import webbrowser
|
112
100
|
|
113
101
|
webbrowser.open(url)
|
114
102
|
|
115
103
|
|
116
|
-
def _open_browser_with_command(command, url):
|
104
|
+
def _open_browser_with_command(command: str, url: str) -> None:
|
117
105
|
cmd_line = [command, url]
|
118
106
|
with open(os.devnull, "w") as devnull:
|
119
107
|
subprocess.Popen(cmd_line, stdout=devnull, stderr=subprocess.STDOUT)
|
@@ -167,13 +155,13 @@ def index_(iterable: Iterable[_Value], x: _Value) -> int:
|
|
167
155
|
elif isinstance(value, float) and isinstance(x, float):
|
168
156
|
if abs(x - value) < FLOAT_EQUALITY_EPSILON:
|
169
157
|
return i
|
170
|
-
raise ValueError("{} is not in iterable"
|
158
|
+
raise ValueError(f"{str(x)} is not in iterable")
|
171
159
|
|
172
160
|
|
173
161
|
_Key = TypeVar("_Key", bound=str)
|
174
162
|
|
175
163
|
|
176
|
-
def lower_clean_dict_keys(dict: Mapping[_Key, _Value]) ->
|
164
|
+
def lower_clean_dict_keys(dict: Mapping[_Key, _Value]) -> dict[str, _Value]:
|
177
165
|
return {k.lower().strip(): v for k, v in dict.items()}
|
178
166
|
|
179
167
|
|
@@ -182,7 +170,7 @@ class Error(Exception):
|
|
182
170
|
pass
|
183
171
|
|
184
172
|
|
185
|
-
def calc_md5(s:
|
173
|
+
def calc_md5(s: bytes | str) -> str:
|
186
174
|
"""Return the md5 hash of the given string."""
|
187
175
|
h = hashlib.new("md5", **HASHLIB_KWARGS)
|
188
176
|
|
@@ -193,8 +181,8 @@ def calc_md5(s: Union[bytes, str]) -> str:
|
|
193
181
|
|
194
182
|
|
195
183
|
def exclude_keys_in_dict(
|
196
|
-
d:
|
197
|
-
) ->
|
184
|
+
d: dict[str, Any], keys_to_exclude: list[str]
|
185
|
+
) -> dict[str, Any]:
|
198
186
|
"""Returns new object but without keys defined in keys_to_exclude"""
|
199
187
|
return {
|
200
188
|
key: value for key, value in d.items() if key.lower() not in keys_to_exclude
|
@@ -202,20 +190,18 @@ def exclude_keys_in_dict(
|
|
202
190
|
|
203
191
|
|
204
192
|
def extract_key_query_params(
|
205
|
-
query_params:
|
206
|
-
) ->
|
193
|
+
query_params: dict[str, list[str]], param_key: str
|
194
|
+
) -> set[str]:
|
207
195
|
"""Extracts key (case-insensitive) query params from Dict, and returns them as Set of str."""
|
208
|
-
return
|
209
|
-
|
210
|
-
|
211
|
-
for
|
212
|
-
|
213
|
-
|
214
|
-
if key.lower() == param_key and query_params.get(key)
|
215
|
-
]
|
216
|
-
for item in sublist
|
196
|
+
return {
|
197
|
+
item.lower()
|
198
|
+
for sublist in [
|
199
|
+
[value.lower() for value in query_params[key]]
|
200
|
+
for key in query_params.keys()
|
201
|
+
if key.lower() == param_key and query_params.get(key)
|
217
202
|
]
|
218
|
-
|
203
|
+
for item in sublist
|
204
|
+
}
|
219
205
|
|
220
206
|
|
221
207
|
K = TypeVar("K")
|
@@ -227,7 +213,7 @@ class TimedCleanupCache(TTLCache, Generic[K, V]):
|
|
227
213
|
|
228
214
|
def __init__(self, *args, **kwargs):
|
229
215
|
super().__init__(*args, **kwargs)
|
230
|
-
self._task:
|
216
|
+
self._task: asyncio.Task[Any] | None = None
|
231
217
|
|
232
218
|
def __setitem__(self, key: K, value: V) -> None:
|
233
219
|
# Set an expiration task to run periodically
|
@@ -39,7 +39,7 @@ from __future__ import annotations
|
|
39
39
|
|
40
40
|
import os
|
41
41
|
import threading
|
42
|
-
from typing import Callable,
|
42
|
+
from typing import Callable, Final, cast
|
43
43
|
|
44
44
|
from blinker import ANY, Signal
|
45
45
|
from watchdog import events
|
@@ -109,13 +109,13 @@ class EventBasedPathWatcher:
|
|
109
109
|
path_watcher.stop_watching_path(self._path, self._on_changed)
|
110
110
|
|
111
111
|
|
112
|
-
class _MultiPathWatcher
|
112
|
+
class _MultiPathWatcher:
|
113
113
|
"""Watches multiple paths."""
|
114
114
|
|
115
|
-
_singleton:
|
115
|
+
_singleton: _MultiPathWatcher | None = None
|
116
116
|
|
117
117
|
@classmethod
|
118
|
-
def get_singleton(cls) ->
|
118
|
+
def get_singleton(cls) -> _MultiPathWatcher:
|
119
119
|
"""Return the singleton _MultiPathWatcher object.
|
120
120
|
|
121
121
|
Instantiates one if necessary.
|
@@ -127,18 +127,18 @@ class _MultiPathWatcher(object):
|
|
127
127
|
return cast("_MultiPathWatcher", _MultiPathWatcher._singleton)
|
128
128
|
|
129
129
|
# Don't allow constructor to be called more than once.
|
130
|
-
def __new__(cls) ->
|
130
|
+
def __new__(cls) -> _MultiPathWatcher:
|
131
131
|
"""Constructor."""
|
132
132
|
if _MultiPathWatcher._singleton is not None:
|
133
133
|
raise RuntimeError("Use .get_singleton() instead")
|
134
|
-
return super(
|
134
|
+
return super().__new__(cls)
|
135
135
|
|
136
136
|
def __init__(self) -> None:
|
137
137
|
"""Constructor."""
|
138
138
|
_MultiPathWatcher._singleton = self
|
139
139
|
|
140
140
|
# Map of folder_to_watch -> _FolderEventHandler.
|
141
|
-
self._folder_handlers:
|
141
|
+
self._folder_handlers: dict[str, _FolderEventHandler] = {}
|
142
142
|
|
143
143
|
# Used for mutation of _folder_handlers dict
|
144
144
|
self._lock = threading.Lock()
|
@@ -218,7 +218,7 @@ class _MultiPathWatcher(object):
|
|
218
218
|
self._observer.join(timeout=5)
|
219
219
|
|
220
220
|
|
221
|
-
class WatchedPath
|
221
|
+
class WatchedPath:
|
222
222
|
"""Emits notifications when a single path is modified."""
|
223
223
|
|
224
224
|
def __init__(
|
@@ -254,8 +254,8 @@ class _FolderEventHandler(events.FileSystemEventHandler):
|
|
254
254
|
"""
|
255
255
|
|
256
256
|
def __init__(self) -> None:
|
257
|
-
super(
|
258
|
-
self._watched_paths:
|
257
|
+
super().__init__()
|
258
|
+
self._watched_paths: dict[str, WatchedPath] = {}
|
259
259
|
self._lock = threading.Lock() # for watched_paths mutations
|
260
260
|
self.watch: ObservedWatch | None = None
|
261
261
|
|