streamlit-nightly 1.45.2.dev20250512__py3-none-any.whl → 1.45.2.dev20250514__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 (154) hide show
  1. streamlit/__init__.py +1 -0
  2. streamlit/auth_util.py +6 -6
  3. streamlit/commands/echo.py +5 -3
  4. streamlit/commands/execution_control.py +30 -30
  5. streamlit/components/v1/custom_component.py +2 -2
  6. streamlit/config.py +7 -7
  7. streamlit/config_util.py +5 -6
  8. streamlit/delta_generator.py +4 -1
  9. streamlit/deprecation_util.py +5 -5
  10. streamlit/elements/doc_string.py +4 -6
  11. streamlit/elements/heading.py +3 -4
  12. streamlit/elements/html.py +3 -4
  13. streamlit/elements/lib/built_in_chart_utils.py +14 -11
  14. streamlit/elements/lib/image_utils.py +2 -3
  15. streamlit/elements/lib/options_selector_utils.py +1 -2
  16. streamlit/elements/lib/pandas_styler_utils.py +1 -3
  17. streamlit/elements/lib/policies.py +1 -1
  18. streamlit/elements/lib/subtitle_utils.py +6 -9
  19. streamlit/elements/map.py +1 -2
  20. streamlit/elements/plotly_chart.py +1 -2
  21. streamlit/elements/spinner.py +1 -1
  22. streamlit/elements/toast.py +1 -2
  23. streamlit/elements/vega_charts.py +1 -1
  24. streamlit/elements/widgets/chat.py +25 -27
  25. streamlit/elements/widgets/file_uploader.py +2 -2
  26. streamlit/elements/widgets/radio.py +4 -5
  27. streamlit/elements/widgets/select_slider.py +9 -11
  28. streamlit/elements/widgets/slider.py +1 -1
  29. streamlit/elements/write.py +2 -2
  30. streamlit/error_util.py +15 -8
  31. streamlit/errors.py +10 -7
  32. streamlit/file_util.py +6 -3
  33. streamlit/git_util.py +26 -21
  34. streamlit/hello/dataframe_demo.py +1 -1
  35. streamlit/hello/mapping_demo.py +1 -1
  36. streamlit/hello/plotting_demo.py +3 -3
  37. streamlit/hello/streamlit_app.py +1 -1
  38. streamlit/hello/utils.py +2 -1
  39. streamlit/navigation/page.py +5 -6
  40. streamlit/runtime/app_session.py +4 -4
  41. streamlit/runtime/caching/cache_data_api.py +2 -2
  42. streamlit/runtime/caching/cache_errors.py +1 -1
  43. streamlit/runtime/caching/cache_resource_api.py +1 -1
  44. streamlit/runtime/caching/cache_utils.py +3 -3
  45. streamlit/runtime/caching/cached_message_replay.py +1 -2
  46. streamlit/runtime/caching/hashing.py +2 -2
  47. streamlit/runtime/caching/storage/in_memory_cache_storage_wrapper.py +2 -3
  48. streamlit/runtime/context.py +1 -5
  49. streamlit/runtime/credentials.py +4 -4
  50. streamlit/runtime/forward_msg_queue.py +1 -1
  51. streamlit/runtime/media_file_manager.py +1 -2
  52. streamlit/runtime/memory_uploaded_file_manager.py +1 -1
  53. streamlit/runtime/metrics_util.py +1 -1
  54. streamlit/runtime/runtime.py +1 -1
  55. streamlit/runtime/scriptrunner/exec_code.py +1 -1
  56. streamlit/runtime/scriptrunner/script_cache.py +1 -1
  57. streamlit/runtime/scriptrunner/script_runner.py +9 -2
  58. streamlit/runtime/scriptrunner_utils/script_requests.py +3 -3
  59. streamlit/runtime/scriptrunner_utils/script_run_context.py +3 -3
  60. streamlit/runtime/secrets.py +6 -7
  61. streamlit/runtime/state/query_params.py +1 -1
  62. streamlit/runtime/state/session_state.py +1 -2
  63. streamlit/runtime/stats.py +1 -1
  64. streamlit/static/index.html +1 -1
  65. streamlit/static/static/js/{ErrorOutline.esm.Cfhrjz42.js → ErrorOutline.esm.DbGVRvJi.js} +1 -1
  66. streamlit/static/static/js/{FileDownload.esm.BN5DkI-d.js → FileDownload.esm.Dsazfko3.js} +1 -1
  67. streamlit/static/static/js/{FileHelper.BWWhRdUs.js → FileHelper.MycXbml-.js} +1 -1
  68. streamlit/static/static/js/{FormClearHelper.CHPGUkGG.js → FormClearHelper.BBCnWP4b.js} +1 -1
  69. streamlit/static/static/js/{Hooks.DjxyUmgD.js → Hooks.Cogxcj3O.js} +1 -1
  70. streamlit/static/static/js/{InputInstructions.Bkai2tFZ.js → InputInstructions.DmFmv5Ss.js} +1 -1
  71. streamlit/static/static/js/{ProgressBar.DFiqS51i.js → ProgressBar.CL8D7fKU.js} +1 -1
  72. streamlit/static/static/js/{RenderInPortalIfExists.DWTzV71R.js → RenderInPortalIfExists.BIF2_x-k.js} +1 -1
  73. streamlit/static/static/js/{Toolbar.Dk2A3VxL.js → Toolbar.BiePqUs0.js} +1 -1
  74. streamlit/static/static/js/{base-input.DfiT3r4p.js → base-input.9-IewVJN.js} +1 -1
  75. streamlit/static/static/js/{checkbox.DLXFjls2.js → checkbox.CvxVkFoK.js} +1 -1
  76. streamlit/static/static/js/{createSuper.n2DV0o-4.js → createSuper.CcYwpbOm.js} +1 -1
  77. streamlit/static/static/js/{data-grid-overlay-editor.v1LF25Ml.js → data-grid-overlay-editor.DVakjLUQ.js} +1 -1
  78. streamlit/static/static/js/{downloader.CI8EFE9Y.js → downloader.DUDYpW4X.js} +1 -1
  79. streamlit/static/static/js/{es6.CH6Tf3Uw.js → es6.Dd8C3gJG.js} +2 -2
  80. streamlit/static/static/js/{iframeResizer.contentWindow.VCjyiSg6.js → iframeResizer.contentWindow.ElqrcVSG.js} +1 -1
  81. streamlit/static/static/js/{index.7XN_jSTW.js → index.3TsDLcVz.js} +1 -1
  82. streamlit/static/static/js/{index.CmsMgepL.js → index.8U8I-dVE.js} +1 -1
  83. streamlit/static/static/js/{index.BROoC18J.js → index.B5gxNAgv.js} +1 -1
  84. streamlit/static/static/js/{index.B1j5m20t.js → index.BANNX-Et.js} +1 -1
  85. streamlit/static/static/js/{index.9p279joF.js → index.BRTdJWEL.js} +1 -1
  86. streamlit/static/static/js/{index.DoM9A12Z.js → index.BYGvkzYg.js} +6 -6
  87. streamlit/static/static/js/{index.DXDmqevk.js → index.Bgid2lLN.js} +1 -1
  88. streamlit/static/static/js/{index.BgY_Js0s.js → index.BkpDVBQw.js} +1 -1
  89. streamlit/static/static/js/{index.CXpQxU0G.js → index.Bud-F2Rk.js} +1 -1
  90. streamlit/static/static/js/{index.B-Q1qQil.js → index.C-wDYZmi.js} +1 -1
  91. streamlit/static/static/js/{index.C1P3O0oI.js → index.C44ecW4y.js} +1 -1
  92. streamlit/static/static/js/{index.STF1QdPr.js → index.CDxF0FlW.js} +1 -1
  93. streamlit/static/static/js/{index.Ovig-AMR.js → index.CM8qhnIu.js} +5 -5
  94. streamlit/static/static/js/{index.LqvX_Kr6.js → index.Chn8rXFO.js} +1 -1
  95. streamlit/static/static/js/{index.CR4eM0Q3.js → index.CkOK3vMg.js} +1 -1
  96. streamlit/static/static/js/{index.DMDjQhhk.js → index.CssifhIa.js} +1 -1
  97. streamlit/static/static/js/{index.SPkHHODG.js → index.CtEWZzBM.js} +1 -1
  98. streamlit/static/static/js/{index.uhNJX5pn.js → index.CwLlrvyN.js} +1 -1
  99. streamlit/static/static/js/{index.nmbrjghZ.js → index.D0fj09K-.js} +1 -1
  100. streamlit/static/static/js/{index.BFEA8ufN.js → index.D5Y8GQ-0.js} +1 -1
  101. streamlit/static/static/js/{index.DcH46Eo2.js → index.D8g5_NeN.js} +1 -1
  102. streamlit/static/static/js/{index.DM_jnlWC.js → index.DK1C5mv_.js} +1 -1
  103. streamlit/static/static/js/{index.uN3TP5oq.js → index.DNeEyPk6.js} +1 -1
  104. streamlit/static/static/js/{index.DKsDSPTo.js → index.DWBlm6kP.js} +1 -1
  105. streamlit/static/static/js/{index.C9ORVZvA.js → index.DWL3vnFa.js} +1 -1
  106. streamlit/static/static/js/{index.D1DxKfIm.js → index.DX_Td1Hq.js} +1 -1
  107. streamlit/static/static/js/{index.hFB9saa3.js → index.DfYxhBCm.js} +1 -1
  108. streamlit/static/static/js/{index.C1TEsRV0.js → index.DgQ-i_4o.js} +75 -75
  109. streamlit/static/static/js/{index.D_Bv6KD1.js → index.DiE_wY_P.js} +1 -1
  110. streamlit/static/static/js/{index.DUU38l7N.js → index.DrVpZAT_.js} +1 -1
  111. streamlit/static/static/js/{index.BEE4v1Vc.js → index.Dxf51cqQ.js} +1 -1
  112. streamlit/static/static/js/{index.jZkr87Ly.js → index.Ogd9LUng.js} +1 -1
  113. streamlit/static/static/js/{index.ZuW7Olhm.js → index.PYQDVW05.js} +1 -1
  114. streamlit/static/static/js/{index.DgeyRl4J.js → index.QqgppQA_.js} +1 -1
  115. streamlit/static/static/js/{index.D1An7GDs.js → index.rR2rxOdw.js} +1 -1
  116. streamlit/static/static/js/{index.BWVpiUBA.js → index.uT7_kc4D.js} +1 -1
  117. streamlit/static/static/js/{index.Cdsxte9t.js → index.y8UOtxmw.js} +1 -1
  118. streamlit/static/static/js/{input.BAfiLByr.js → input.D1uIuNvR.js} +1 -1
  119. streamlit/static/static/js/{memory.CvD1KGKJ.js → memory.C_YLF4Fx.js} +1 -1
  120. streamlit/static/static/js/{mergeWith.Dy4BuY-h.js → mergeWith.BrhEAUIQ.js} +1 -1
  121. streamlit/static/static/js/{number-overlay-editor.Bl84FLfp.js → number-overlay-editor.Cl4hS5U2.js} +1 -1
  122. streamlit/static/static/js/{possibleConstructorReturn.gffiKeDQ.js → possibleConstructorReturn.BizCfnoE.js} +1 -1
  123. streamlit/static/static/js/{sandbox.BXw8ya9t.js → sandbox.BYlf4D-n.js} +1 -1
  124. streamlit/static/static/js/{textarea.DNNNKi6n.js → textarea.BvMrgzVs.js} +1 -1
  125. streamlit/static/static/js/{timepicker.CgHlrhoy.js → timepicker.8sMF8VpM.js} +1 -1
  126. streamlit/static/static/js/{toConsumableArray.MtZ-3vir.js → toConsumableArray.Cl96Bc5x.js} +1 -1
  127. streamlit/static/static/js/{uniqueId.CFcd6g0d.js → uniqueId.BoXr82qs.js} +1 -1
  128. streamlit/static/static/js/{useBasicWidgetState.DadZUraL.js → useBasicWidgetState.DYpB4KjS.js} +1 -1
  129. streamlit/static/static/js/{useOnInputChange.V6d5TCFH.js → useOnInputChange.D17AAeVI.js} +1 -1
  130. streamlit/static/static/js/{withFullScreenWrapper.8qpius26.js → withFullScreenWrapper.Lq8QUQxx.js} +1 -1
  131. streamlit/temporary_directory.py +2 -2
  132. streamlit/testing/v1/app_test.py +2 -2
  133. streamlit/testing/v1/element_tree.py +7 -9
  134. streamlit/testing/v1/local_script_runner.py +1 -2
  135. streamlit/url_util.py +1 -1
  136. streamlit/watcher/folder_black_list.py +1 -1
  137. streamlit/watcher/local_sources_watcher.py +5 -3
  138. streamlit/watcher/path_watcher.py +1 -1
  139. streamlit/watcher/polling_path_watcher.py +1 -1
  140. streamlit/watcher/util.py +6 -5
  141. streamlit/web/bootstrap.py +4 -4
  142. streamlit/web/cli.py +13 -13
  143. streamlit/web/server/app_static_file_handler.py +1 -1
  144. streamlit/web/server/authlib_tornado_integration.py +6 -1
  145. streamlit/web/server/oauth_authlib_routes.py +3 -3
  146. streamlit/web/server/oidc_mixin.py +15 -3
  147. streamlit/web/server/routes.py +11 -11
  148. streamlit/web/server/stats_request_handler.py +2 -2
  149. {streamlit_nightly-1.45.2.dev20250512.dist-info → streamlit_nightly-1.45.2.dev20250514.dist-info}/METADATA +1 -1
  150. {streamlit_nightly-1.45.2.dev20250512.dist-info → streamlit_nightly-1.45.2.dev20250514.dist-info}/RECORD +154 -154
  151. {streamlit_nightly-1.45.2.dev20250512.dist-info → streamlit_nightly-1.45.2.dev20250514.dist-info}/WHEEL +1 -1
  152. {streamlit_nightly-1.45.2.dev20250512.data → streamlit_nightly-1.45.2.dev20250514.data}/scripts/streamlit.cmd +0 -0
  153. {streamlit_nightly-1.45.2.dev20250512.dist-info → streamlit_nightly-1.45.2.dev20250514.dist-info}/entry_points.txt +0 -0
  154. {streamlit_nightly-1.45.2.dev20250512.dist-info → streamlit_nightly-1.45.2.dev20250514.dist-info}/top_level.txt +0 -0
@@ -341,12 +341,11 @@ class RadioMixin:
341
341
  def handle_captions(caption: str | None) -> str:
342
342
  if caption is None:
343
343
  return ""
344
- elif isinstance(caption, str):
344
+ if isinstance(caption, str):
345
345
  return caption
346
- else:
347
- raise StreamlitAPIException(
348
- f"Radio captions must be strings. Passed type: {type(caption).__name__}"
349
- )
346
+ raise StreamlitAPIException(
347
+ f"Radio captions must be strings. Passed type: {type(caption).__name__}"
348
+ )
350
349
 
351
350
  session_state = get_session_state().filtered_state
352
351
  if key is not None and key in session_state and session_state[key] is None:
@@ -102,8 +102,7 @@ class SelectSliderSerde(Generic[T]):
102
102
  if start > end:
103
103
  slider_value = [end, start]
104
104
  return slider_value
105
- else:
106
- return [index_(self.options, v)]
105
+ return [index_(self.options, v)]
107
106
 
108
107
 
109
108
  class SelectSliderMixin:
@@ -367,15 +366,14 @@ class SelectSliderMixin:
367
366
  if start > end:
368
367
  slider_value = [end, start]
369
368
  return slider_value
370
- else:
371
- # Simplify future logic by always making value a list
372
- try:
373
- return [index_(opt, v)]
374
- except ValueError:
375
- if value is not None:
376
- raise
377
-
378
- return [0]
369
+ # Simplify future logic by always making value a list
370
+ try:
371
+ return [index_(opt, v)]
372
+ except ValueError:
373
+ if value is not None:
374
+ raise
375
+
376
+ return [0]
379
377
 
380
378
  # Convert element to index of the elements
381
379
  slider_value = as_index_list(value)
@@ -692,7 +692,7 @@ class SliderMixin:
692
692
  if single_value:
693
693
  value = [value]
694
694
 
695
- def value_to_generic_type(v):
695
+ def value_to_generic_type(v: Any) -> SliderProto.DataType.ValueType:
696
696
  if isinstance(v, Integral):
697
697
  return SUPPORTED_TYPES[Integral]
698
698
  if isinstance(v, Real):
@@ -156,7 +156,7 @@ class WriteMixin:
156
156
  streamed_response: str = ""
157
157
  written_content: list[Any] = StreamingOutput()
158
158
 
159
- def flush_stream_response():
159
+ def flush_stream_response() -> None:
160
160
  """Write the full response to the app."""
161
161
  nonlocal streamed_response
162
162
  nonlocal stream_container
@@ -428,7 +428,7 @@ class WriteMixin:
428
428
  "when called as `st.write()` or `st.sidebar.write()`."
429
429
  )
430
430
 
431
- def flush_buffer():
431
+ def flush_buffer() -> None:
432
432
  if string_buffer:
433
433
  text_content = " ".join(string_buffer)
434
434
  # The usage of empty here prevents
streamlit/error_util.py CHANGED
@@ -14,7 +14,7 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
- from typing import Final
17
+ from typing import Any, Final
18
18
 
19
19
  import streamlit
20
20
  from streamlit import config
@@ -26,17 +26,24 @@ _LOGGER: Final = get_logger(__name__)
26
26
 
27
27
 
28
28
  def _print_rich_exception(e: BaseException) -> None:
29
- from rich import box, panel
29
+ from rich.box import Box
30
+ from rich.panel import Panel
30
31
 
31
32
  # Monkey patch the panel to use our custom box style
32
- class ConfigurablePanel(panel.Panel):
33
+ class ConfigurablePanel(Panel):
33
34
  def __init__(
34
35
  self,
35
- renderable,
36
- box=box.Box("────\n \n────\n \n────\n────\n \n────\n"),
37
- **kwargs,
38
- ):
39
- super().__init__(renderable, box, **kwargs)
36
+ renderable: Any,
37
+ box: Box | None = None,
38
+ **kwargs: Any,
39
+ ) -> None:
40
+ super().__init__(
41
+ renderable,
42
+ box
43
+ if box is not None
44
+ else Box("────\n \n────\n \n────\n────\n \n────\n"),
45
+ **kwargs,
46
+ )
40
47
 
41
48
  from rich import traceback as rich_traceback
42
49
 
streamlit/errors.py CHANGED
@@ -20,6 +20,7 @@ from typing import TYPE_CHECKING, Any, Literal
20
20
  from streamlit import util
21
21
 
22
22
  if TYPE_CHECKING:
23
+ from collections.abc import Collection
23
24
  from datetime import date, time
24
25
 
25
26
 
@@ -140,7 +141,7 @@ class StreamlitAPIWarning(StreamlitAPIException, Warning):
140
141
  instead.
141
142
  """
142
143
 
143
- def __init__(self, *args):
144
+ def __init__(self, *args: Any) -> None:
144
145
  super().__init__(*args)
145
146
  import inspect
146
147
  import traceback
@@ -157,7 +158,7 @@ class StreamlitModuleNotFoundError(StreamlitAPIWarning):
157
158
  that is not one of our core dependencies.
158
159
  """
159
160
 
160
- def __init__(self, module_name, *args):
161
+ def __init__(self, module_name: str, *args: Any) -> None:
161
162
  message = (
162
163
  f'This Streamlit command requires module "{module_name}" to be installed.'
163
164
  )
@@ -220,7 +221,7 @@ class StreamlitInvalidURLError(LocalizableStreamlitException):
220
221
  class StreamlitInvalidColumnSpecError(LocalizableStreamlitException):
221
222
  """Exception raised when no weights are specified, or a negative weight is specified."""
222
223
 
223
- def __init__(self):
224
+ def __init__(self) -> None:
224
225
  super().__init__(
225
226
  "The `spec` argument to `st.columns` must be either a "
226
227
  "positive integer (number of columns) or a list of positive numbers (width ratios of the columns). "
@@ -370,7 +371,7 @@ class StreamlitInvalidNumberFormatError(LocalizableStreamlitException):
370
371
  class StreamlitMissingPageLabelError(LocalizableStreamlitException):
371
372
  """Exception raised when a page_link is created without a label."""
372
373
 
373
- def __init__(self):
374
+ def __init__(self) -> None:
374
375
  super().__init__(
375
376
  "The `label` param is required for external links used with `st.page_link` - please provide a `label`."
376
377
  )
@@ -409,7 +410,7 @@ class StreamlitPageNotFoundError(LocalizableStreamlitException):
409
410
  class StreamlitFragmentWidgetsNotAllowedOutsideError(LocalizableStreamlitException):
410
411
  """Exception raised when the fragment attempts to write to an element outside of its container."""
411
412
 
412
- def __init__(self):
413
+ def __init__(self) -> None:
413
414
  super().__init__("Fragments cannot write widgets to outside containers.")
414
415
 
415
416
 
@@ -418,7 +419,7 @@ class StreamlitInvalidFormCallbackError(LocalizableStreamlitException):
418
419
  the `st.form_submit_button`.
419
420
  """
420
421
 
421
- def __init__(self):
422
+ def __init__(self) -> None:
422
423
  super().__init__(
423
424
  "Within a form, callbacks can only be defined on `st.form_submit_button`. "
424
425
  "Defining callbacks on other widgets inside a form is not allowed."
@@ -436,7 +437,9 @@ class StreamlitValueAssignmentNotAllowedError(LocalizableStreamlitException):
436
437
 
437
438
 
438
439
  class StreamlitInvalidColorError(LocalizableStreamlitException):
439
- def __init__(self, color):
440
+ def __init__(
441
+ self, color: str | Collection[Any] | tuple[int, int, int, int]
442
+ ) -> None:
440
443
  super().__init__(
441
444
  "This does not look like a valid color: {color}.\n\n"
442
445
  "Colors must be in one of the following formats:"
streamlit/file_util.py CHANGED
@@ -19,11 +19,14 @@ import errno
19
19
  import io
20
20
  import os
21
21
  from pathlib import Path
22
- from typing import Final
22
+ from typing import IO, TYPE_CHECKING, Any, Final
23
23
 
24
24
  from streamlit import env_util, errors
25
25
  from streamlit.string_util import is_binary_string
26
26
 
27
+ if TYPE_CHECKING:
28
+ from collections.abc import Generator
29
+
27
30
  # Configuration and credentials are stored inside the ~/.streamlit folder
28
31
  CONFIG_FOLDER_NAME: Final = ".streamlit"
29
32
 
@@ -63,7 +66,7 @@ def get_encoded_file_data(
63
66
 
64
67
 
65
68
  @contextlib.contextmanager
66
- def streamlit_read(path, binary=False):
69
+ def streamlit_read(path: str, binary: bool = False) -> Generator[IO[Any], None, None]:
67
70
  """Opens a context to read this file relative to the streamlit path.
68
71
 
69
72
  For example:
@@ -88,7 +91,7 @@ def streamlit_read(path, binary=False):
88
91
 
89
92
 
90
93
  @contextlib.contextmanager
91
- def streamlit_write(path, binary=False):
94
+ def streamlit_write(path: str, binary: bool = False) -> Generator[IO[Any], None, None]:
92
95
  """Opens a file for writing within the streamlit path, and
93
96
  ensuring that the path exists.
94
97
 
streamlit/git_util.py CHANGED
@@ -16,10 +16,13 @@ from __future__ import annotations
16
16
 
17
17
  import os
18
18
  import re
19
- from typing import Any
19
+ from typing import TYPE_CHECKING, cast
20
20
 
21
21
  from streamlit import util
22
22
 
23
+ if TYPE_CHECKING:
24
+ from git import Commit, Remote, RemoteReference, Repo
25
+
23
26
  # Github has two URLs, one that is https and one that is ssh
24
27
  GITHUB_HTTP_URL = r"^https://(www\.)?github.com/(.+)/(.+)(?:.git)?$"
25
28
  GITHUB_SSH_URL = r"^git@github.com:(.+)/(.+)(?:.git)?$"
@@ -31,7 +34,9 @@ MIN_GIT_VERSION = (2, 7, 0)
31
34
 
32
35
 
33
36
  class GitRepo:
34
- def __init__(self, path):
37
+ repo: Repo | None
38
+
39
+ def __init__(self, path: str) -> None:
35
40
  # If we have a valid repo, git_version will be a tuple
36
41
  # of 3+ ints: (major, minor, patch, possible_additional_patch_number)
37
42
  self.git_version: tuple[int, ...] | None = None
@@ -39,11 +44,7 @@ class GitRepo:
39
44
  try:
40
45
  import git
41
46
 
42
- # GitPython is not fully typed, and mypy is outputting inconsistent
43
- # type errors on Mac and Linux. We bypass type checking entirely
44
- # by redeclaring the `git` import as an "Any".
45
- git_package: Any = git
46
- self.repo = git_package.Repo(path, search_parent_directories=True)
47
+ self.repo = git.Repo(path, search_parent_directories=True)
47
48
  self.git_version = self.repo.git.version_info
48
49
 
49
50
  if self.git_version >= MIN_GIT_VERSION:
@@ -69,8 +70,8 @@ class GitRepo:
69
70
  )
70
71
 
71
72
  @property
72
- def tracking_branch(self):
73
- if not self.is_valid():
73
+ def tracking_branch(self) -> RemoteReference | None:
74
+ if self.repo is None or not self.is_valid():
74
75
  return None
75
76
 
76
77
  if self.is_head_detached:
@@ -79,41 +80,45 @@ class GitRepo:
79
80
  return self.repo.active_branch.tracking_branch()
80
81
 
81
82
  @property
82
- def untracked_files(self):
83
- if not self.is_valid():
83
+ def untracked_files(self) -> list[str] | None:
84
+ if self.repo is None or not self.is_valid():
84
85
  return None
85
86
 
86
87
  return self.repo.untracked_files
87
88
 
88
89
  @property
89
- def is_head_detached(self):
90
- if not self.is_valid():
90
+ def is_head_detached(self) -> bool:
91
+ if self.repo is None or not self.is_valid():
91
92
  return False
92
93
 
93
94
  return self.repo.head.is_detached
94
95
 
95
96
  @property
96
- def uncommitted_files(self):
97
- if not self.is_valid():
97
+ def uncommitted_files(self) -> list[str] | None:
98
+ if self.repo is None or not self.is_valid():
98
99
  return None
99
100
 
100
- return [item.a_path for item in self.repo.index.diff(None)]
101
+ return [cast("str", item.a_path) for item in self.repo.index.diff(None)]
101
102
 
102
103
  @property
103
- def ahead_commits(self):
104
- if not self.is_valid():
104
+ def ahead_commits(self) -> list[Commit] | None:
105
+ if self.repo is None or not self.is_valid():
105
106
  return None
106
107
 
107
108
  try:
108
- remote, branch_name = self.get_tracking_branch_remote()
109
+ tracking_branch_info = self.get_tracking_branch_remote()
110
+ if tracking_branch_info is None:
111
+ return None
112
+
113
+ remote, branch_name = tracking_branch_info
109
114
  remote_branch = f"{remote.name}/{branch_name}"
110
115
 
111
116
  return list(self.repo.iter_commits(f"{remote_branch}..{branch_name}"))
112
117
  except Exception:
113
118
  return []
114
119
 
115
- def get_tracking_branch_remote(self):
116
- if not self.is_valid():
120
+ def get_tracking_branch_remote(self) -> tuple[Remote, str] | None:
121
+ if self.repo is None or not self.is_valid():
117
122
  return None
118
123
 
119
124
  tracking_branch = self.tracking_branch
@@ -21,7 +21,7 @@ import streamlit as st
21
21
  from streamlit.hello.utils import show_code
22
22
 
23
23
 
24
- def data_frame_demo():
24
+ def data_frame_demo() -> None:
25
25
  @st.cache_data
26
26
  def get_un_data() -> pd.DataFrame:
27
27
  AWS_BUCKET_URL = "https://streamlit-demo-data.s3-us-west-2.amazonaws.com"
@@ -21,7 +21,7 @@ import streamlit as st
21
21
  from streamlit.hello.utils import show_code
22
22
 
23
23
 
24
- def mapping_demo():
24
+ def mapping_demo() -> None:
25
25
  @st.cache_data
26
26
  def from_data_file(filename: str) -> pd.DataFrame:
27
27
  url = (
@@ -20,14 +20,14 @@ import streamlit as st
20
20
  from streamlit.hello.utils import show_code
21
21
 
22
22
 
23
- def plotting_demo():
23
+ def plotting_demo() -> None:
24
24
  progress_bar = st.sidebar.progress(0)
25
25
  status_text = st.sidebar.empty()
26
- last_rows = np.random.randn(1, 1)
26
+ last_rows = np.random.randn(1, 1) # noqa: NPY002
27
27
  chart = st.line_chart(last_rows)
28
28
 
29
29
  for i in range(1, 101):
30
- new_rows = last_rows[-1, :] + np.random.randn(5, 1).cumsum(axis=0)
30
+ new_rows = last_rows[-1, :] + np.random.randn(5, 1).cumsum(axis=0) # noqa: NPY002
31
31
  status_text.text(f"{i}% complete")
32
32
  chart.add_rows(new_rows)
33
33
  progress_bar.progress(i)
@@ -20,7 +20,7 @@ dir_path = Path(__file__).parent
20
20
 
21
21
 
22
22
  # Note that this needs to be in a method so we can have an e2e playwright test.
23
- def run():
23
+ def run() -> None:
24
24
  page = st.navigation(
25
25
  [
26
26
  st.Page(
streamlit/hello/utils.py CHANGED
@@ -14,11 +14,12 @@
14
14
 
15
15
  import inspect
16
16
  import textwrap
17
+ from typing import Any, Callable
17
18
 
18
19
  import streamlit as st
19
20
 
20
21
 
21
- def show_code(demo):
22
+ def show_code(demo: Callable[..., Any]) -> None:
22
23
  """Showing the code of the demo."""
23
24
  show_code = st.sidebar.checkbox("Show code", True)
24
25
  if show_code:
@@ -289,12 +289,11 @@ class StreamlitPage:
289
289
  if callable(self._page):
290
290
  self._page()
291
291
  return
292
- else:
293
- code = ctx.pages_manager.get_page_script_byte_code(str(self._page))
294
- module = types.ModuleType("__main__")
295
- # We want __file__ to be the string path to the script
296
- module.__dict__["__file__"] = str(self._page)
297
- exec(code, module.__dict__) # noqa: S102
292
+ code = ctx.pages_manager.get_page_script_byte_code(str(self._page))
293
+ module = types.ModuleType("__main__")
294
+ # We want __file__ to be the string path to the script
295
+ module.__dict__["__file__"] = str(self._page)
296
+ exec(code, module.__dict__) # noqa: S102
298
297
 
299
298
  @property
300
299
  def _script_hash(self) -> str:
@@ -151,7 +151,7 @@ class AppSession:
151
151
  self._client_state = ClientState()
152
152
 
153
153
  self._local_sources_watcher: LocalSourcesWatcher | None = None
154
- self._stop_config_listener: Callable[[], bool] | None = None
154
+ self._stop_config_listener: Callable[[], None] | None = None
155
155
  self._stop_pages_listener: Callable[[], None] | None = None
156
156
 
157
157
  if config.get_option("server.fileWatcherType") != "none":
@@ -792,12 +792,12 @@ class AppSession:
792
792
  msg.git_info_changed.branch = branch
793
793
  msg.git_info_changed.module = module
794
794
 
795
- msg.git_info_changed.untracked_files[:] = repo.untracked_files
796
- msg.git_info_changed.uncommitted_files[:] = repo.uncommitted_files
795
+ msg.git_info_changed.untracked_files[:] = repo.untracked_files or []
796
+ msg.git_info_changed.uncommitted_files[:] = repo.uncommitted_files or []
797
797
 
798
798
  if repo.is_head_detached:
799
799
  msg.git_info_changed.state = GitInfo.GitStates.HEAD_DETACHED
800
- elif len(repo.ahead_commits) > 0:
800
+ elif repo.ahead_commits and len(repo.ahead_commits) > 0:
801
801
  msg.git_info_changed.state = GitInfo.GitStates.AHEAD_OF_REMOTE
802
802
  else:
803
803
  msg.git_info_changed.state = GitInfo.GitStates.DEFAULT
@@ -147,7 +147,7 @@ class CachedDataFuncInfo(CachedFuncInfo):
147
147
  class DataCaches(CacheStatsProvider):
148
148
  """Manages all DataCache instances."""
149
149
 
150
- def __init__(self):
150
+ def __init__(self) -> None:
151
151
  self._caches_lock = threading.Lock()
152
152
  self._function_caches: dict[str, DataCache] = {}
153
153
 
@@ -566,7 +566,7 @@ class CacheDataAPI:
566
566
  if experimental_allow_widgets:
567
567
  show_widget_replay_deprecation("cache_data")
568
568
 
569
- def wrapper(f):
569
+ def wrapper(f): # noqa: ANN001, ANN202
570
570
  return make_cached_func_wrapper(
571
571
  CachedDataFuncInfo(
572
572
  func=f,
@@ -30,7 +30,7 @@ def get_cached_func_name_md(func: Any) -> str:
30
30
  """Get markdown representation of the function name."""
31
31
  if hasattr(func, "__name__"):
32
32
  return f"`{func.__name__}()`"
33
- elif hasattr(type(func), "__name__"):
33
+ if hasattr(type(func), "__name__"):
34
34
  return f"`{type(func).__name__}`"
35
35
  return f"`{type(func)}`"
36
36
 
@@ -69,7 +69,7 @@ def _equal_validate_funcs(a: ValidateFunc | None, b: ValidateFunc | None) -> boo
69
69
  class ResourceCaches(CacheStatsProvider):
70
70
  """Manages all ResourceCache instances."""
71
71
 
72
- def __init__(self):
72
+ def __init__(self) -> None:
73
73
  self._caches_lock = threading.Lock()
74
74
  self._function_caches: dict[str, ResourceCache] = {}
75
75
 
@@ -65,7 +65,7 @@ TTLCACHE_TIMER = time.monotonic
65
65
  class Cache:
66
66
  """Function cache interface. Caches persist across script runs."""
67
67
 
68
- def __init__(self):
68
+ def __init__(self) -> None:
69
69
  self._value_locks: dict[str, threading.Lock] = defaultdict(threading.Lock)
70
70
  self._value_locks_lock = threading.Lock()
71
71
 
@@ -196,7 +196,7 @@ class CachedFunc:
196
196
  def __repr__(self) -> str:
197
197
  return f"<CachedFunc: {self._info.func}>"
198
198
 
199
- def __get__(self, instance, owner=None):
199
+ def __get__(self, instance: Any, owner: Any | None = None) -> Any:
200
200
  """CachedFunc implements descriptor protocol to support cache methods."""
201
201
  if instance is None:
202
202
  return self
@@ -346,7 +346,7 @@ class CachedFunc:
346
346
  return_value=computed_value, func=self._info.func
347
347
  )
348
348
 
349
- def clear(self, *args, **kwargs):
349
+ def clear(self, *args: Any, **kwargs: Any) -> None:
350
350
  """Clear the cached function's associated cache.
351
351
 
352
352
  If no arguments are passed, Streamlit will clear all values cached for
@@ -218,8 +218,7 @@ class CachedMessageReplayContext(threading.local):
218
218
  """
219
219
  if len(self._seen_dg_stack) > 0 and acting_on_id in self._seen_dg_stack[-1]:
220
220
  return acting_on_id
221
- else:
222
- return invoked_id
221
+ return invoked_id
223
222
 
224
223
  def save_image_data(
225
224
  self, image_data: bytes | str, mimetype: str, image_id: str
@@ -182,7 +182,7 @@ class _HashStack:
182
182
  This causes the "in" to crash since it expects a boolean.
183
183
  """
184
184
 
185
- def __init__(self):
185
+ def __init__(self) -> None:
186
186
  self._stack: collections.OrderedDict[int, list[Any]] = collections.OrderedDict()
187
187
  # A function that we decorate with streamlit cache
188
188
  # primitive (st.cache_data or st.cache_resource).
@@ -213,7 +213,7 @@ class _HashStack:
213
213
  class _HashStacks:
214
214
  """Stacks of what has been hashed, with at most 1 stack per thread."""
215
215
 
216
- def __init__(self):
216
+ def __init__(self) -> None:
217
217
  self._stacks: weakref.WeakKeyDictionary[threading.Thread, _HashStack] = (
218
218
  weakref.WeakKeyDictionary()
219
219
  )
@@ -131,9 +131,8 @@ class InMemoryCacheStorageWrapper(CacheStorage):
131
131
  _LOGGER.debug("Memory cache HIT: %s", key)
132
132
  return entry
133
133
 
134
- else:
135
- _LOGGER.debug("Memory cache MISS: %s", key)
136
- raise CacheStorageKeyNotFoundError("Key not found in mem cache")
134
+ _LOGGER.debug("Memory cache MISS: %s", key)
135
+ raise CacheStorageKeyNotFoundError("Key not found in mem cache")
137
136
 
138
137
  def _write_to_mem_cache(self, key: str, entry_bytes: bytes) -> None:
139
138
  with self._mem_cache_lock:
@@ -328,11 +328,7 @@ class ContextProxy:
328
328
  url_without_page_prefix = maybe_trim_page_path(
329
329
  url_from_frontend, ctx.pages_manager
330
330
  )
331
- url_with_page_prefix = maybe_add_page_path(
332
- url_without_page_prefix, ctx.pages_manager
333
- )
334
-
335
- return url_with_page_prefix
331
+ return maybe_add_page_path(url_without_page_prefix, ctx.pages_manager)
336
332
 
337
333
  @property
338
334
  @gather_metrics("context.ip_address")
@@ -66,7 +66,7 @@ Collecting usage statistics. To deactivate, set browser.gatherUsageStats to fals
66
66
  """
67
67
 
68
68
 
69
- def _send_email(email: str) -> None:
69
+ def _send_email(email: str | None) -> None:
70
70
  """Send the user's email for metrics, if submitted."""
71
71
  import requests
72
72
 
@@ -124,15 +124,15 @@ class Credentials:
124
124
 
125
125
  return cast("Credentials", Credentials._singleton)
126
126
 
127
- def __init__(self):
127
+ def __init__(self) -> None:
128
128
  """Initialize class."""
129
129
  if Credentials._singleton is not None:
130
130
  raise RuntimeError(
131
131
  "Credentials already initialized. Use .get_current() instead"
132
132
  )
133
133
 
134
- self.activation = None
135
- self._conf_file = _get_credential_file_path()
134
+ self.activation: _Activation | None = None
135
+ self._conf_file: str = _get_credential_file_path()
136
136
 
137
137
  Credentials._singleton = self
138
138
 
@@ -41,7 +41,7 @@ class ForwardMsgQueue:
41
41
  """
42
42
  ForwardMsgQueue._before_enqueue_msg = before_enqueue_msg
43
43
 
44
- def __init__(self):
44
+ def __init__(self) -> None:
45
45
  self._queue: list[ForwardMsg] = []
46
46
  # A mapping of (delta_path -> _queue.indexof(msg)) for each
47
47
  # Delta message in the queue. We use this for coalescing
@@ -38,8 +38,7 @@ def _get_session_id() -> str:
38
38
  # "streamlit run myscript.py". In which case the session ID doesn't
39
39
  # matter and can just be a constant, as there's only ever "session".
40
40
  return "dontcare"
41
- else:
42
- return ctx.session_id
41
+ return ctx.session_id
43
42
 
44
43
 
45
44
  class MediaFileMetadata:
@@ -92,7 +92,7 @@ class MemoryUploadedFileManager(UploadedFileManager):
92
92
 
93
93
  self.file_storage[session_id][file.file_id] = file
94
94
 
95
- def remove_file(self, session_id, file_id):
95
+ def remove_file(self, session_id: str, file_id: str) -> None:
96
96
  """Remove file with given file_id associated with a given session."""
97
97
  session_storage = self.file_storage[session_id]
98
98
  session_storage.pop(file_id, None)
@@ -228,7 +228,7 @@ class Installation:
228
228
  cls._instance = Installation()
229
229
  return cls._instance
230
230
 
231
- def __init__(self):
231
+ def __init__(self) -> None:
232
232
  self.installation_id_v3 = str(
233
233
  uuid.uuid5(uuid.NAMESPACE_DNS, _get_machine_id_v3())
234
234
  )
@@ -313,7 +313,7 @@ class Runtime:
313
313
 
314
314
  async_objs = self._get_async_objs()
315
315
 
316
- def stop_on_eventloop():
316
+ def stop_on_eventloop() -> None:
317
317
  if self._state in (RuntimeState.STOPPING, RuntimeState.STOPPED):
318
318
  return
319
319
 
@@ -50,7 +50,7 @@ class modified_sys_path: # noqa: N801
50
50
  def __repr__(self) -> str:
51
51
  return util.repr_(self)
52
52
 
53
- def __enter__(self):
53
+ def __enter__(self) -> None:
54
54
  if self._main_script_path not in sys.path:
55
55
  sys.path.insert(0, self._main_script_path)
56
56
  self._added_path = True