streamlit-nightly 1.45.1.dev20250508__py3-none-any.whl → 1.45.1.dev20250510__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 (208) hide show
  1. streamlit/auth_util.py +3 -3
  2. streamlit/cli_util.py +3 -2
  3. streamlit/commands/execution_control.py +1 -1
  4. streamlit/commands/logo.py +2 -2
  5. streamlit/commands/navigation.py +6 -5
  6. streamlit/commands/page_config.py +3 -1
  7. streamlit/components/types/base_custom_component.py +7 -7
  8. streamlit/components/v1/custom_component.py +6 -6
  9. streamlit/config.py +9 -9
  10. streamlit/config_option.py +2 -2
  11. streamlit/connections/base_connection.py +3 -3
  12. streamlit/connections/snowflake_connection.py +5 -5
  13. streamlit/connections/snowpark_connection.py +3 -3
  14. streamlit/connections/sql_connection.py +9 -10
  15. streamlit/cursor.py +6 -6
  16. streamlit/delta_generator.py +7 -6
  17. streamlit/delta_generator_singletons.py +3 -3
  18. streamlit/deprecation_util.py +1 -1
  19. streamlit/elements/arrow.py +4 -5
  20. streamlit/elements/code.py +1 -1
  21. streamlit/elements/dialog_decorator.py +3 -3
  22. streamlit/elements/doc_string.py +20 -20
  23. streamlit/elements/layouts.py +26 -7
  24. streamlit/elements/lib/built_in_chart_utils.py +38 -40
  25. streamlit/elements/lib/color_util.py +3 -3
  26. streamlit/elements/lib/column_types.py +4 -4
  27. streamlit/elements/lib/dialog.py +2 -2
  28. streamlit/elements/lib/event_utils.py +1 -1
  29. streamlit/elements/lib/image_utils.py +1 -1
  30. streamlit/elements/lib/mutable_status_container.py +1 -1
  31. streamlit/elements/lib/options_selector_utils.py +2 -2
  32. streamlit/elements/lib/policies.py +3 -3
  33. streamlit/elements/lib/utils.py +5 -5
  34. streamlit/elements/metric.py +1 -1
  35. streamlit/elements/progress.py +9 -12
  36. streamlit/elements/vega_charts.py +3 -3
  37. streamlit/elements/widgets/audio_input.py +1 -1
  38. streamlit/elements/widgets/button.py +1 -1
  39. streamlit/elements/widgets/button_group.py +4 -4
  40. streamlit/elements/widgets/camera_input.py +1 -1
  41. streamlit/elements/widgets/checkbox.py +2 -2
  42. streamlit/elements/widgets/color_picker.py +1 -1
  43. streamlit/elements/widgets/data_editor.py +3 -3
  44. streamlit/elements/widgets/file_uploader.py +1 -1
  45. streamlit/elements/widgets/multiselect.py +3 -3
  46. streamlit/elements/widgets/number_input.py +2 -2
  47. streamlit/elements/widgets/radio.py +1 -1
  48. streamlit/elements/widgets/select_slider.py +1 -1
  49. streamlit/elements/widgets/selectbox.py +2 -2
  50. streamlit/elements/widgets/slider.py +19 -17
  51. streamlit/elements/widgets/text_widgets.py +2 -2
  52. streamlit/elements/widgets/time_widgets.py +2 -2
  53. streamlit/elements/write.py +3 -6
  54. streamlit/errors.py +34 -21
  55. streamlit/external/langchain/streamlit_callback_handler.py +2 -2
  56. streamlit/file_util.py +8 -8
  57. streamlit/git_util.py +2 -2
  58. streamlit/hello/dataframe_demo.py +1 -1
  59. streamlit/hello/mapping_demo.py +1 -1
  60. streamlit/navigation/page.py +1 -1
  61. streamlit/proto/Block_pb2.py +38 -29
  62. streamlit/proto/Block_pb2.pyi +68 -4
  63. streamlit/proto/DataFrame_pb2.pyi +1 -1
  64. streamlit/proto/GapSize_pb2.py +29 -0
  65. streamlit/proto/GapSize_pb2.pyi +70 -0
  66. streamlit/proto/HeightConfig_pb2.py +27 -0
  67. streamlit/proto/HeightConfig_pb2.pyi +48 -0
  68. streamlit/proto/NamedDataSet_pb2.pyi +1 -1
  69. streamlit/proto/WidthConfig_pb2.py +2 -2
  70. streamlit/proto/WidthConfig_pb2.pyi +15 -1
  71. streamlit/runtime/app_session.py +2 -2
  72. streamlit/runtime/caching/cache_data_api.py +9 -5
  73. streamlit/runtime/caching/cache_errors.py +3 -3
  74. streamlit/runtime/caching/cache_resource_api.py +7 -7
  75. streamlit/runtime/caching/cache_utils.py +9 -9
  76. streamlit/runtime/caching/cached_message_replay.py +1 -1
  77. streamlit/runtime/caching/hashing.py +70 -74
  78. streamlit/runtime/caching/legacy_cache_api.py +1 -1
  79. streamlit/runtime/caching/storage/in_memory_cache_storage_wrapper.py +3 -1
  80. streamlit/runtime/caching/storage/local_disk_cache_storage.py +1 -1
  81. streamlit/runtime/connection_factory.py +15 -15
  82. streamlit/runtime/context.py +2 -2
  83. streamlit/runtime/credentials.py +3 -3
  84. streamlit/runtime/fragment.py +3 -4
  85. streamlit/runtime/media_file_manager.py +2 -2
  86. streamlit/runtime/memory_media_file_storage.py +1 -1
  87. streamlit/runtime/memory_uploaded_file_manager.py +1 -1
  88. streamlit/runtime/metrics_util.py +5 -6
  89. streamlit/runtime/pages_manager.py +3 -3
  90. streamlit/runtime/runtime.py +1 -1
  91. streamlit/runtime/runtime_util.py +2 -2
  92. streamlit/runtime/scriptrunner/exec_code.py +10 -3
  93. streamlit/runtime/scriptrunner/magic.py +13 -8
  94. streamlit/runtime/scriptrunner/script_runner.py +2 -2
  95. streamlit/runtime/scriptrunner_utils/exceptions.py +1 -1
  96. streamlit/runtime/scriptrunner_utils/script_run_context.py +6 -5
  97. streamlit/runtime/secrets.py +8 -11
  98. streamlit/runtime/state/query_params.py +2 -2
  99. streamlit/runtime/state/query_params_proxy.py +1 -1
  100. streamlit/runtime/state/safe_session_state.py +2 -2
  101. streamlit/runtime/state/session_state.py +17 -15
  102. streamlit/runtime/stats.py +1 -1
  103. streamlit/runtime/uploaded_file_manager.py +1 -1
  104. streamlit/source_util.py +3 -4
  105. streamlit/static/index.html +1 -1
  106. streamlit/static/static/js/{ErrorOutline.esm.C9UoaGEN.js → ErrorOutline.esm.BewaDzzJ.js} +1 -1
  107. streamlit/static/static/js/{FileDownload.esm.DoToR9q0.js → FileDownload.esm.D6ilL7v-.js} +1 -1
  108. streamlit/static/static/js/{FileHelper.Bt4VJ--Q.js → FileHelper.q7erXtkb.js} +1 -1
  109. streamlit/static/static/js/{FormClearHelper.D5PbW8FI.js → FormClearHelper.Dd0v0IXt.js} +1 -1
  110. streamlit/static/static/js/{Hooks.DgkQ2Xp9.js → Hooks.CchmJZGs.js} +1 -1
  111. streamlit/static/static/js/{InputInstructions.DLnLhwHI.js → InputInstructions.DI9h4PJ7.js} +1 -1
  112. streamlit/static/static/js/{ProgressBar.BtSgh_K-.js → ProgressBar.DfcVR_JA.js} +1 -1
  113. streamlit/static/static/js/{RenderInPortalIfExists.CjdyBvQX.js → RenderInPortalIfExists.BAkT-LV5.js} +1 -1
  114. streamlit/static/static/js/{Toolbar.CAYIzVZk.js → Toolbar.CNzefYiX.js} +1 -1
  115. streamlit/static/static/js/{base-input.CD4xW4_9.js → base-input.BmA1ZV9Y.js} +1 -1
  116. streamlit/static/static/js/{checkbox.Ba4jj5dR.js → checkbox.mT4TKcAG.js} +1 -1
  117. streamlit/static/static/js/{createSuper.BBGT9Ijd.js → createSuper.Duo43uhY.js} +1 -1
  118. streamlit/static/static/js/{data-grid-overlay-editor.CYuk1Aj7.js → data-grid-overlay-editor.CY3l_gmP.js} +1 -1
  119. streamlit/static/static/js/{downloader.DM9KEOCw.js → downloader.CM5asV91.js} +1 -1
  120. streamlit/static/static/js/{es6.FqM62T4b.js → es6.uiOeU51e.js} +2 -2
  121. streamlit/static/static/js/{iframeResizer.contentWindow.s2B09mw2.js → iframeResizer.contentWindow.ClkMmI3q.js} +1 -1
  122. streamlit/static/static/js/{index.Cwtbhfaf.js → index.1tDlzcmX.js} +1 -1
  123. streamlit/static/static/js/index.3d64wPzr.js +1 -0
  124. streamlit/static/static/js/{index.DQi04JYE.js → index.B-oXGsp7.js} +1 -1
  125. streamlit/static/static/js/{index.0pkoyBcb.js → index.B2EfQ-qM.js} +1 -1
  126. streamlit/static/static/js/{index.DkGCnTMe.js → index.B5wTpdet.js} +1 -1
  127. streamlit/static/static/js/{index.DG8IxVeM.js → index.B6y8ns6u.js} +2 -2
  128. streamlit/static/static/js/{index.B9FiDQ3U.js → index.BArkjssT.js} +1 -1
  129. streamlit/static/static/js/{index.CpDFZQ4Y.js → index.BPK3aPVr.js} +1 -1
  130. streamlit/static/static/js/index.BWubePhz.js +1 -0
  131. streamlit/static/static/js/{index.T5LKPcND.js → index.BmBUBll0.js} +1 -1
  132. streamlit/static/static/js/{index.BMXmhMlZ.js → index.BnmoQ0mJ.js} +1 -1
  133. streamlit/static/static/js/{index.BsjuUMyW.js → index.C1_voZpt.js} +1 -1
  134. streamlit/static/static/js/index.C6tuB1Tp.js +2 -0
  135. streamlit/static/static/js/{index.BoMRR3tN.js → index.CB8SwV8L.js} +1 -1
  136. streamlit/static/static/js/{index.CEKMSkSh.js → index.CXmZFP__.js} +36 -36
  137. streamlit/static/static/js/{index.DTi8Lw0k.js → index.CYAmxIg2.js} +1 -1
  138. streamlit/static/static/js/{index.DMrO9G6A.js → index.D-zMZsin.js} +1 -1
  139. streamlit/static/static/js/{index.JTeVe9GQ.js → index.D56z-_rt.js} +1 -1
  140. streamlit/static/static/js/index.D6AKDy4z.js +1 -0
  141. streamlit/static/static/js/{index.BFqpCk2P.js → index.D9lEoddJ.js} +1 -1
  142. streamlit/static/static/js/index.DAEzs_UL.js +1 -0
  143. streamlit/static/static/js/{index.BDTYk2an.js → index.DLO5_tVd.js} +1 -1
  144. streamlit/static/static/js/{index.BY7-qCf5.js → index.DLyB6OQM.js} +1 -1
  145. streamlit/static/static/js/index.DNWXtL99.js +1 -0
  146. streamlit/static/static/js/index.DbgE46VI.js +1 -0
  147. streamlit/static/static/js/{index.b9kK7Vzl.js → index.DeLPvnoy.js} +1 -1
  148. streamlit/static/static/js/{index.CH9XN_-G.js → index.DeeFVG0Y.js} +2 -2
  149. streamlit/static/static/js/{index.BVA8TXNT.js → index.Dhu_cVNQ.js} +1 -1
  150. streamlit/static/static/js/{index.R0peMEpV.js → index.Dj8nqcpI.js} +1 -1
  151. streamlit/static/static/js/{index.D9FvPPrI.js → index.DpWg6flp.js} +1 -1
  152. streamlit/static/static/js/{index.CeiCniCg.js → index.IqYlA3jn.js} +1 -1
  153. streamlit/static/static/js/{index.DSDkXosb.js → index.JA6OF_5t.js} +2 -2
  154. streamlit/static/static/js/{index.C2qCX1Lh.js → index.PoIwzrI7.js} +151 -151
  155. streamlit/static/static/js/{index.CqaahZPf.js → index.SW3uv22k.js} +1 -1
  156. streamlit/static/static/js/{index.DWaB7Scf.js → index.WlA_Ju7i.js} +1 -1
  157. streamlit/static/static/js/{index.CP2PmB93.js → index.blwBIOHe.js} +1 -1
  158. streamlit/static/static/js/{index.CyE1OdOj.js → index.wiodyGjO.js} +1 -1
  159. streamlit/static/static/js/{input.DMOGBelK.js → input.B3uNJm6d.js} +1 -1
  160. streamlit/static/static/js/{memory.DmCktBGW.js → memory.BWtwV556.js} +1 -1
  161. streamlit/static/static/js/{mergeWith.DeWTsJ5h.js → mergeWith.BeTmYGS_.js} +1 -1
  162. streamlit/static/static/js/{number-overlay-editor.DDFelcUP.js → number-overlay-editor.MW9-6kFx.js} +1 -1
  163. streamlit/static/static/js/{possibleConstructorReturn.CYJtAqB-.js → possibleConstructorReturn.ZgHiGHSO.js} +1 -1
  164. streamlit/static/static/js/{sandbox.CfaU9Ih9.js → sandbox.BZyTt4zT.js} +1 -1
  165. streamlit/static/static/js/{textarea.7hWYKDw2.js → textarea.CgvEg9Xi.js} +1 -1
  166. streamlit/static/static/js/{timepicker.DZsgZ9oE.js → timepicker.CHPC9KOb.js} +1 -1
  167. streamlit/static/static/js/{toConsumableArray.CqWB4Jry.js → toConsumableArray.6GvveewD.js} +1 -1
  168. streamlit/static/static/js/{uniqueId.DQ533D9O.js → uniqueId.BV5h1uCx.js} +1 -1
  169. streamlit/static/static/js/{useBasicWidgetState.-99xbU_o.js → useBasicWidgetState.DzE2MsN8.js} +1 -1
  170. streamlit/static/static/js/{useOnInputChange.B4G2Q7Bu.js → useOnInputChange.sGAnyCSU.js} +1 -1
  171. streamlit/static/static/js/{withFullScreenWrapper.BJQZ2aNc.js → withFullScreenWrapper.Bh08pTH8.js} +1 -1
  172. streamlit/string_util.py +6 -7
  173. streamlit/temporary_directory.py +12 -3
  174. streamlit/testing/v1/app_test.py +11 -6
  175. streamlit/testing/v1/element_tree.py +134 -158
  176. streamlit/testing/v1/local_script_runner.py +5 -5
  177. streamlit/testing/v1/util.py +11 -4
  178. streamlit/type_util.py +3 -4
  179. streamlit/user_info.py +3 -2
  180. streamlit/util.py +1 -1
  181. streamlit/vendor/pympler/asizeof.py +1 -1
  182. streamlit/watcher/event_based_path_watcher.py +1 -1
  183. streamlit/watcher/folder_black_list.py +1 -1
  184. streamlit/watcher/local_sources_watcher.py +5 -5
  185. streamlit/watcher/path_watcher.py +1 -1
  186. streamlit/web/cli.py +12 -11
  187. streamlit/web/server/browser_websocket_handler.py +1 -1
  188. streamlit/web/server/component_request_handler.py +1 -1
  189. streamlit/web/server/media_file_handler.py +2 -1
  190. streamlit/web/server/oauth_authlib_routes.py +2 -2
  191. streamlit/web/server/oidc_mixin.py +13 -6
  192. streamlit/web/server/routes.py +3 -3
  193. streamlit/web/server/server.py +1 -1
  194. streamlit/web/server/server_util.py +7 -6
  195. streamlit/web/server/upload_file_request_handler.py +5 -5
  196. {streamlit_nightly-1.45.1.dev20250508.dist-info → streamlit_nightly-1.45.1.dev20250510.dist-info}/METADATA +1 -1
  197. {streamlit_nightly-1.45.1.dev20250508.dist-info → streamlit_nightly-1.45.1.dev20250510.dist-info}/RECORD +201 -197
  198. {streamlit_nightly-1.45.1.dev20250508.dist-info → streamlit_nightly-1.45.1.dev20250510.dist-info}/WHEEL +1 -1
  199. streamlit/static/static/js/index.CCD4LJ9Q.js +0 -1
  200. streamlit/static/static/js/index.CbLZDRQu.js +0 -1
  201. streamlit/static/static/js/index.D9qEk5xd.js +0 -1
  202. streamlit/static/static/js/index.DTXSsTgK.js +0 -1
  203. streamlit/static/static/js/index.DqVjOqxm.js +0 -1
  204. streamlit/static/static/js/index.RHbaxsqm.js +0 -1
  205. streamlit/static/static/js/index.hT9gkW3a.js +0 -2
  206. {streamlit_nightly-1.45.1.dev20250508.data → streamlit_nightly-1.45.1.dev20250510.data}/scripts/streamlit.cmd +0 -0
  207. {streamlit_nightly-1.45.1.dev20250508.dist-info → streamlit_nightly-1.45.1.dev20250510.dist-info}/entry_points.txt +0 -0
  208. {streamlit_nightly-1.45.1.dev20250508.dist-info → streamlit_nightly-1.45.1.dev20250510.dist-info}/top_level.txt +0 -0
@@ -53,7 +53,7 @@ class UnhashableParamError(StreamlitAPIException):
53
53
  arg_name: str | None,
54
54
  arg_value: Any,
55
55
  orig_exc: BaseException,
56
- ):
56
+ ) -> None:
57
57
  msg = self._create_message(cache_type, func, arg_name, arg_value)
58
58
  super().__init__(msg)
59
59
  self.with_traceback(orig_exc.__traceback__)
@@ -99,7 +99,7 @@ class CacheReplayClosureError(StreamlitAPIException):
99
99
  self,
100
100
  cache_type: CacheType,
101
101
  cached_func: FunctionType,
102
- ):
102
+ ) -> None:
103
103
  func_name = get_cached_func_name_md(cached_func)
104
104
  decorator_name = get_decorator_api_name(cache_type)
105
105
 
@@ -121,7 +121,7 @@ How to fix this:
121
121
 
122
122
 
123
123
  class UnserializableReturnValueError(MarkdownFormattedException):
124
- def __init__(self, func: FunctionType, return_value: FunctionType):
124
+ def __init__(self, func: FunctionType, return_value: FunctionType) -> None:
125
125
  MarkdownFormattedException.__init__(
126
126
  self,
127
127
  f"""
@@ -151,7 +151,7 @@ class CachedResourceFuncInfo(CachedFuncInfo):
151
151
  ttl: float | timedelta | str | None,
152
152
  validate: ValidateFunc | None,
153
153
  hash_funcs: HashFuncsDict | None = None,
154
- ):
154
+ ) -> None:
155
155
  super().__init__(
156
156
  func,
157
157
  show_spinner=show_spinner,
@@ -189,7 +189,7 @@ class CacheResourceAPI:
189
189
  and st.cache_resource.clear().
190
190
  """
191
191
 
192
- def __init__(self, decorator_metric_name: str):
192
+ def __init__(self, decorator_metric_name: str) -> None:
193
193
  """Create a CacheResourceAPI instance.
194
194
 
195
195
  Parameters
@@ -234,7 +234,7 @@ class CacheResourceAPI:
234
234
  validate: ValidateFunc | None = None,
235
235
  experimental_allow_widgets: bool = False,
236
236
  hash_funcs: HashFuncsDict | None = None,
237
- ):
237
+ ) -> F | Callable[[F], F]:
238
238
  return self._decorator(
239
239
  func,
240
240
  ttl=ttl,
@@ -255,7 +255,7 @@ class CacheResourceAPI:
255
255
  validate: ValidateFunc | None,
256
256
  experimental_allow_widgets: bool,
257
257
  hash_funcs: HashFuncsDict | None = None,
258
- ):
258
+ ) -> F | Callable[[F], F]:
259
259
  """Decorator to cache functions that return global resources (e.g. database connections, ML models).
260
260
 
261
261
  Cached objects are shared across all users, sessions, and reruns. They
@@ -417,9 +417,9 @@ class CacheResourceAPI:
417
417
  # Support passing the params via function decorator, e.g.
418
418
  # @st.cache_resource(show_spinner=False)
419
419
  if func is None:
420
- return lambda f: make_cached_func_wrapper(
420
+ return lambda f: make_cached_func_wrapper( # type: ignore
421
421
  CachedResourceFuncInfo(
422
- func=f,
422
+ func=f, # type: ignore
423
423
  show_spinner=show_spinner,
424
424
  max_entries=max_entries,
425
425
  ttl=ttl,
@@ -455,7 +455,7 @@ class ResourceCache(Cache):
455
455
  ttl_seconds: float,
456
456
  validate: ValidateFunc | None,
457
457
  display_name: str,
458
- ):
458
+ ) -> None:
459
459
  super().__init__()
460
460
  self.key = key
461
461
  self.display_name = display_name
@@ -100,7 +100,7 @@ class Cache:
100
100
  with self._value_locks_lock:
101
101
  return self._value_locks[value_key]
102
102
 
103
- def clear(self, key: str | None = None):
103
+ def clear(self, key: str | None = None) -> None:
104
104
  """Clear values from this cache.
105
105
  If no argument is passed, all items are cleared from the cache.
106
106
  A key can be passed to clear that key from the cache only.
@@ -130,7 +130,7 @@ class CachedFuncInfo:
130
130
  func: FunctionType,
131
131
  show_spinner: bool | str,
132
132
  hash_funcs: HashFuncsDict | None,
133
- ):
133
+ ) -> None:
134
134
  self.func = func
135
135
  self.show_spinner = show_spinner
136
136
  self.hash_funcs = hash_funcs
@@ -167,17 +167,17 @@ class BoundCachedFunc:
167
167
  decorated function is a class method.
168
168
  """
169
169
 
170
- def __init__(self, cached_func: CachedFunc, instance: Any):
170
+ def __init__(self, cached_func: CachedFunc, instance: Any) -> None:
171
171
  self._cached_func = cached_func
172
172
  self._instance = instance
173
173
 
174
- def __call__(self, *args, **kwargs) -> Any:
174
+ def __call__(self, *args: Any, **kwargs: Any) -> Any:
175
175
  return self._cached_func(self._instance, *args, **kwargs)
176
176
 
177
- def __repr__(self):
177
+ def __repr__(self) -> str:
178
178
  return f"<BoundCachedFunc: {self._cached_func._info.func} of {self._instance}>"
179
179
 
180
- def clear(self, *args, **kwargs):
180
+ def clear(self, *args: Any, **kwargs: Any) -> None:
181
181
  if args or kwargs:
182
182
  # The instance is required as first parameter to allow
183
183
  # args to be correctly resolved to the parameter names:
@@ -189,11 +189,11 @@ class BoundCachedFunc:
189
189
 
190
190
 
191
191
  class CachedFunc:
192
- def __init__(self, info: CachedFuncInfo):
192
+ def __init__(self, info: CachedFuncInfo) -> None:
193
193
  self._info = info
194
194
  self._function_key = _make_function_key(info.cache_type, info.func)
195
195
 
196
- def __repr__(self):
196
+ def __repr__(self) -> str:
197
197
  return f"<CachedFunc: {self._info.func}>"
198
198
 
199
199
  def __get__(self, instance, owner=None):
@@ -203,7 +203,7 @@ class CachedFunc:
203
203
 
204
204
  return functools.update_wrapper(BoundCachedFunc(self, instance), self)
205
205
 
206
- def __call__(self, *args, **kwargs) -> Any:
206
+ def __call__(self, *args: Any, **kwargs: Any) -> Any:
207
207
  """The wrapper. We'll only call our underlying function on a cache miss."""
208
208
 
209
209
  spinner_message: str | None = None
@@ -121,7 +121,7 @@ class CachedMessageReplayContext(threading.local):
121
121
  of this class across multiple threads.
122
122
  """
123
123
 
124
- def __init__(self, cache_type: CacheType):
124
+ def __init__(self, cache_type: CacheType) -> None:
125
125
  self._cached_message_stack: list[list[MsgData]] = []
126
126
  self._seen_dg_stack: list[set[str]] = []
127
127
  self._most_recent_messages: list[MsgData] = []
@@ -34,7 +34,7 @@ import weakref
34
34
  from enum import Enum
35
35
  from re import Pattern
36
36
  from types import MappingProxyType
37
- from typing import Any, Callable, Final, Union, cast
37
+ from typing import TYPE_CHECKING, Any, Callable, Final, Union, cast
38
38
 
39
39
  from typing_extensions import TypeAlias
40
40
 
@@ -44,6 +44,10 @@ from streamlit.runtime.caching.cache_errors import UnhashableTypeError
44
44
  from streamlit.runtime.caching.cache_type import CacheType
45
45
  from streamlit.runtime.uploaded_file_manager import UploadedFile
46
46
 
47
+ if TYPE_CHECKING:
48
+ import numpy.typing as npt
49
+ from PIL.Image import Image
50
+
47
51
  _LOGGER: Final = logger.get_logger(__name__)
48
52
 
49
53
  # If a dataframe has more than this many rows, we consider it large and hash a sample.
@@ -66,11 +70,11 @@ _CYCLE_PLACEHOLDER: Final = (
66
70
  class UserHashError(StreamlitAPIException):
67
71
  def __init__(
68
72
  self,
69
- orig_exc,
70
- object_to_hash,
71
- hash_func,
73
+ orig_exc: BaseException,
74
+ object_to_hash: Any,
75
+ hash_func: Callable[[Any], Any],
72
76
  cache_type: CacheType | None = None,
73
- ):
77
+ ) -> None:
74
78
  self.alternate_name = type(orig_exc).__name__
75
79
  self.hash_func = hash_func
76
80
  self.cache_type = cache_type
@@ -80,7 +84,11 @@ class UserHashError(StreamlitAPIException):
80
84
  super().__init__(msg)
81
85
  self.with_traceback(orig_exc.__traceback__)
82
86
 
83
- def _get_message_from_func(self, orig_exc, cached_func):
87
+ def _get_message_from_func(
88
+ self,
89
+ orig_exc: BaseException,
90
+ cached_func: Any,
91
+ ) -> str:
84
92
  args = self._get_error_message_args(orig_exc, cached_func)
85
93
 
86
94
  return (
@@ -145,7 +153,7 @@ If you think this is actually a Streamlit bug, please
145
153
 
146
154
  def update_hash(
147
155
  val: Any,
148
- hasher,
156
+ hasher: Any,
149
157
  cache_type: CacheType,
150
158
  hash_source: Callable[..., Any] | None = None,
151
159
  hash_funcs: HashFuncsDict | None = None,
@@ -182,13 +190,13 @@ class _HashStack:
182
190
  def __repr__(self) -> str:
183
191
  return util.repr_(self)
184
192
 
185
- def push(self, val: Any):
193
+ def push(self, val: Any) -> None:
186
194
  self._stack[id(val)] = val
187
195
 
188
- def pop(self):
196
+ def pop(self) -> None:
189
197
  self._stack.popitem()
190
198
 
191
- def __contains__(self, val: Any):
199
+ def __contains__(self, val: Any) -> bool:
192
200
  return id(val) in self._stack
193
201
 
194
202
  def pretty_print(self) -> str:
@@ -247,28 +255,20 @@ def _key(obj: Any | None) -> Any:
247
255
  if obj is None:
248
256
  return None
249
257
 
250
- def is_simple(obj):
258
+ def is_simple(obj: Any) -> bool:
251
259
  return (
252
- isinstance(obj, bytes)
253
- or isinstance(obj, bytearray)
254
- or isinstance(obj, str)
255
- or isinstance(obj, float)
256
- or isinstance(obj, int)
257
- or isinstance(obj, bool)
258
- or isinstance(obj, uuid.UUID)
260
+ isinstance(obj, (bytes, bytearray, str, float, int, bool, uuid.UUID))
259
261
  or obj is None
260
262
  )
261
263
 
262
264
  if is_simple(obj):
263
265
  return obj
264
266
 
265
- if isinstance(obj, tuple):
266
- if all(map(is_simple, obj)):
267
- return obj
267
+ if isinstance(obj, tuple) and all(map(is_simple, obj)):
268
+ return obj
268
269
 
269
- if isinstance(obj, list):
270
- if all(map(is_simple, obj)):
271
- return ("__l", tuple(obj))
270
+ if isinstance(obj, list) and all(map(is_simple, obj)):
271
+ return ("__l", tuple(obj))
272
272
 
273
273
  if inspect.isbuiltin(obj) or inspect.isroutine(obj) or inspect.iscode(obj):
274
274
  return id(obj)
@@ -279,7 +279,9 @@ def _key(obj: Any | None) -> Any:
279
279
  class _CacheFuncHasher:
280
280
  """A hasher that can hash objects with cycles."""
281
281
 
282
- def __init__(self, cache_type: CacheType, hash_funcs: HashFuncsDict | None = None):
282
+ def __init__(
283
+ self, cache_type: CacheType, hash_funcs: HashFuncsDict | None = None
284
+ ) -> None:
283
285
  # Can't use types as the keys in the internal _hash_funcs because
284
286
  # we always remove user-written modules from memory when rerunning a
285
287
  # script in order to reload it and grab the latest code changes.
@@ -339,7 +341,7 @@ class _CacheFuncHasher:
339
341
 
340
342
  return b
341
343
 
342
- def update(self, hasher, obj: Any) -> None:
344
+ def update(self, hasher: Any, obj: Any) -> None:
343
345
  """Update the provided hasher with the hash of an object."""
344
346
  b = self.to_bytes(obj)
345
347
  hasher.update(b)
@@ -360,10 +362,10 @@ class _CacheFuncHasher:
360
362
  # deep, so we don't try to hash them at all.
361
363
  return self.to_bytes(id(obj))
362
364
 
363
- elif isinstance(obj, bytes) or isinstance(obj, bytearray):
365
+ if isinstance(obj, bytes) or isinstance(obj, bytearray):
364
366
  return obj
365
367
 
366
- elif type_util.get_fqn_type(obj) in self._hash_funcs:
368
+ if type_util.get_fqn_type(obj) in self._hash_funcs:
367
369
  # Escape hatch for unsupported objects
368
370
  hash_func = self._hash_funcs[type_util.get_fqn_type(obj)]
369
371
  try:
@@ -374,57 +376,59 @@ class _CacheFuncHasher:
374
376
  ) from ex
375
377
  return self.to_bytes(output)
376
378
 
377
- elif isinstance(obj, str):
379
+ if isinstance(obj, str):
378
380
  return obj.encode()
379
381
 
380
- elif isinstance(obj, float):
382
+ if isinstance(obj, float):
381
383
  return _float_to_bytes(obj)
382
384
 
383
- elif isinstance(obj, int):
385
+ if isinstance(obj, int):
384
386
  return _int_to_bytes(obj)
385
387
 
386
- elif isinstance(obj, uuid.UUID):
388
+ if isinstance(obj, uuid.UUID):
387
389
  return obj.bytes
388
390
 
389
- elif isinstance(obj, datetime.datetime):
391
+ if isinstance(obj, datetime.datetime):
390
392
  return obj.isoformat().encode()
391
393
 
392
- elif isinstance(obj, (list, tuple)):
394
+ if isinstance(obj, (list, tuple)):
393
395
  for item in obj:
394
396
  self.update(h, item)
395
397
  return h.digest()
396
398
 
397
- elif isinstance(obj, dict):
399
+ if isinstance(obj, dict):
398
400
  for item in obj.items():
399
401
  self.update(h, item)
400
402
  return h.digest()
401
403
 
402
- elif obj is None:
404
+ if obj is None:
403
405
  return b"0"
404
406
 
405
- elif obj is True:
407
+ if obj is True:
406
408
  return b"1"
407
409
 
408
- elif obj is False:
410
+ if obj is False:
409
411
  return b"0"
410
412
 
411
- elif not isinstance(obj, type) and dataclasses.is_dataclass(obj):
413
+ if not isinstance(obj, type) and dataclasses.is_dataclass(obj):
412
414
  return self.to_bytes(dataclasses.asdict(obj))
413
- elif isinstance(obj, Enum):
415
+ if isinstance(obj, Enum):
414
416
  return str(obj).encode()
415
417
 
416
- elif type_util.is_type(obj, "pandas.core.series.Series"):
418
+ if type_util.is_type(obj, "pandas.core.series.Series"):
417
419
  import pandas as pd
418
420
 
419
- obj = cast("pd.Series", obj)
420
- self.update(h, obj.size)
421
- self.update(h, obj.dtype.name)
421
+ series_obj: pd.Series = cast("pd.Series", obj)
422
+ self.update(h, series_obj.size)
423
+ self.update(h, series_obj.dtype.name)
422
424
 
423
- if len(obj) >= _PANDAS_ROWS_LARGE:
424
- obj = obj.sample(n=_PANDAS_SAMPLE_SIZE, random_state=0)
425
+ if len(series_obj) >= _PANDAS_ROWS_LARGE:
426
+ series_obj = series_obj.sample(n=_PANDAS_SAMPLE_SIZE, random_state=0)
425
427
 
426
428
  try:
427
- self.update(h, pd.util.hash_pandas_object(obj).to_numpy().tobytes())
429
+ self.update(
430
+ h, pd.util.hash_pandas_object(series_obj).to_numpy().tobytes()
431
+ )
428
432
  return h.digest()
429
433
  except TypeError:
430
434
  _LOGGER.warning(
@@ -434,22 +438,22 @@ class _CacheFuncHasher:
434
438
 
435
439
  # Use pickle if pandas cannot hash the object for example if
436
440
  # it contains unhashable objects.
437
- return b"%s" % pickle.dumps(obj, pickle.HIGHEST_PROTOCOL)
441
+ return b"%s" % pickle.dumps(series_obj, pickle.HIGHEST_PROTOCOL)
438
442
 
439
443
  elif type_util.is_type(obj, "pandas.core.frame.DataFrame"):
440
444
  import pandas as pd
441
445
 
442
- obj = cast("pd.DataFrame", obj)
443
- self.update(h, obj.shape)
446
+ df_obj: pd.DataFrame = cast("pd.DataFrame", obj)
447
+ self.update(h, df_obj.shape)
444
448
 
445
- if len(obj) >= _PANDAS_ROWS_LARGE:
446
- obj = obj.sample(n=_PANDAS_SAMPLE_SIZE, random_state=0)
449
+ if len(df_obj) >= _PANDAS_ROWS_LARGE:
450
+ df_obj = df_obj.sample(n=_PANDAS_SAMPLE_SIZE, random_state=0)
447
451
  try:
448
452
  column_hash_bytes = self.to_bytes(
449
- pd.util.hash_pandas_object(obj.dtypes)
453
+ pd.util.hash_pandas_object(df_obj.dtypes)
450
454
  )
451
455
  self.update(h, column_hash_bytes)
452
- values_hash_bytes = self.to_bytes(pd.util.hash_pandas_object(obj))
456
+ values_hash_bytes = self.to_bytes(pd.util.hash_pandas_object(df_obj))
453
457
  self.update(h, values_hash_bytes)
454
458
  return h.digest()
455
459
  except TypeError:
@@ -460,7 +464,7 @@ class _CacheFuncHasher:
460
464
 
461
465
  # Use pickle if pandas cannot hash the object for example if
462
466
  # it contains unhashable objects.
463
- return b"%s" % pickle.dumps(obj, pickle.HIGHEST_PROTOCOL)
467
+ return b"%s" % pickle.dumps(df_obj, pickle.HIGHEST_PROTOCOL)
464
468
 
465
469
  elif type_util.is_type(obj, "polars.series.series.Series"):
466
470
  import polars as pl # type: ignore[import-not-found]
@@ -513,39 +517,32 @@ class _CacheFuncHasher:
513
517
  # it contains unhashable objects.
514
518
  return b"%s" % pickle.dumps(obj, pickle.HIGHEST_PROTOCOL)
515
519
  elif type_util.is_type(obj, "numpy.ndarray"):
516
- import numpy as np
517
-
518
- # write cast type as string to make it work with our Python 3.8 tests
519
- # - can be removed once we sunset support for Python 3.8
520
- obj = cast("np.ndarray[Any, Any]", obj)
521
- self.update(h, obj.shape)
522
- self.update(h, str(obj.dtype))
520
+ np_obj: npt.NDArray[Any] = cast("npt.NDArray[Any]", obj)
521
+ self.update(h, np_obj.shape)
522
+ self.update(h, str(np_obj.dtype))
523
523
 
524
- if obj.size >= _NP_SIZE_LARGE:
524
+ if np_obj.size >= _NP_SIZE_LARGE:
525
525
  import numpy as np
526
526
 
527
527
  state = np.random.RandomState(0)
528
- obj = state.choice(obj.flat, size=_NP_SAMPLE_SIZE)
528
+ np_obj = state.choice(np_obj.flat, size=_NP_SAMPLE_SIZE)
529
529
 
530
- self.update(h, obj.tobytes())
530
+ self.update(h, np_obj.tobytes())
531
531
  return h.digest()
532
532
  elif type_util.is_type(obj, "PIL.Image.Image"):
533
533
  import numpy as np
534
- from PIL.Image import Image # noqa: TC002
535
534
 
536
- obj = cast("Image", obj)
535
+ pil_obj: Image = cast("Image", obj)
537
536
 
538
537
  # we don't just hash the results of obj.tobytes() because we want to use
539
538
  # the sampling logic for numpy data
540
- np_array = np.frombuffer(obj.tobytes(), dtype="uint8")
539
+ np_array = np.frombuffer(pil_obj.tobytes(), dtype="uint8")
541
540
  return self.to_bytes(np_array)
542
541
 
543
542
  elif inspect.isbuiltin(obj):
544
543
  return bytes(obj.__name__.encode())
545
544
 
546
- elif isinstance(obj, MappingProxyType) or isinstance(
547
- obj, collections.abc.ItemsView
548
- ):
545
+ elif isinstance(obj, (MappingProxyType, collections.abc.ItemsView)):
549
546
  return self.to_bytes(dict(obj))
550
547
 
551
548
  elif type_util.is_type(obj, "builtins.getset_descriptor"):
@@ -561,9 +558,8 @@ class _CacheFuncHasher:
561
558
  return h.digest()
562
559
 
563
560
  elif hasattr(obj, "name") and (
564
- isinstance(obj, io.IOBase)
565
561
  # Handle temporary files used during testing
566
- or isinstance(obj, tempfile._TemporaryFileWrapper)
562
+ isinstance(obj, (io.IOBase, tempfile._TemporaryFileWrapper))
567
563
  ):
568
564
  # Hash files as name + last modification date + offset.
569
565
  # NB: we're using hasattr("name") to differentiate between
@@ -579,7 +575,7 @@ class _CacheFuncHasher:
579
575
  elif isinstance(obj, Pattern):
580
576
  return self.to_bytes([obj.pattern, obj.flags])
581
577
 
582
- elif isinstance(obj, io.StringIO) or isinstance(obj, io.BytesIO):
578
+ elif isinstance(obj, (io.StringIO, io.BytesIO)):
583
579
  # Hash in-memory StringIO/BytesIO by their full contents
584
580
  # and seek position.
585
581
  self.update(h, obj.tell())
@@ -40,7 +40,7 @@ def cache(
40
40
  hash_funcs: HashFuncsDict | None = None,
41
41
  max_entries: int | None = None,
42
42
  ttl: float | None = None,
43
- ):
43
+ ) -> F:
44
44
  """Legacy caching decorator (deprecated).
45
45
 
46
46
  Legacy caching with ``st.cache`` has been removed from Streamlit. This is
@@ -57,7 +57,9 @@ class InMemoryCacheStorageWrapper(CacheStorage):
57
57
  it from multiple threads.
58
58
  """
59
59
 
60
- def __init__(self, persist_storage: CacheStorage, context: CacheStorageContext):
60
+ def __init__(
61
+ self, persist_storage: CacheStorage, context: CacheStorageContext
62
+ ) -> None:
61
63
  self.function_key = context.function_key
62
64
  self.function_display_name = context.function_display_name
63
65
  self._ttl_seconds = context.ttl_seconds
@@ -120,7 +120,7 @@ class LocalDiskCacheStorage(CacheStorage):
120
120
  This is the default cache persistence layer for `@st.cache_data`.
121
121
  """
122
122
 
123
- def __init__(self, context: CacheStorageContext):
123
+ def __init__(self, context: CacheStorageContext) -> None:
124
124
  self.function_key = context.function_key
125
125
  self.persist = context.persist
126
126
  self._ttl_seconds = context.ttl_seconds
@@ -38,7 +38,7 @@ if TYPE_CHECKING:
38
38
  # 2. Writing two new @overloads for connection_factory (one for the case where the
39
39
  # only the connection name is specified and another when both name and type are).
40
40
  # 3. Updating test_get_first_party_connection_helper in connection_factory_test.py.
41
- FIRST_PARTY_CONNECTIONS = {
41
+ FIRST_PARTY_CONNECTIONS: Final[dict[str, type[BaseConnection[Any]]]] = {
42
42
  "snowflake": SnowflakeConnection,
43
43
  "snowpark": SnowparkConnection,
44
44
  "sql": SQLConnection,
@@ -65,7 +65,7 @@ def _create_connection(
65
65
  connection_class: type[ConnectionClass],
66
66
  max_entries: int | None = None,
67
67
  ttl: float | timedelta | None = None,
68
- **kwargs,
68
+ **kwargs: Any,
69
69
  ) -> ConnectionClass:
70
70
  """Create an instance of connection_class with the given name and kwargs.
71
71
 
@@ -76,7 +76,7 @@ def _create_connection(
76
76
  """
77
77
 
78
78
  def __create_connection(
79
- name: str, connection_class: type[ConnectionClass], **kwargs
79
+ name: str, connection_class: type[ConnectionClass], **kwargs: Any
80
80
  ) -> ConnectionClass:
81
81
  return connection_class(connection_name=name, **kwargs)
82
82
 
@@ -103,7 +103,7 @@ def _create_connection(
103
103
  return __create_connection(name, connection_class, **kwargs)
104
104
 
105
105
 
106
- def _get_first_party_connection(connection_class: str):
106
+ def _get_first_party_connection(connection_class: str) -> type[BaseConnection[Any]]:
107
107
  if connection_class in FIRST_PARTY_CONNECTIONS:
108
108
  return FIRST_PARTY_CONNECTIONS[connection_class]
109
109
 
@@ -119,7 +119,7 @@ def connection_factory(
119
119
  max_entries: int | None = None,
120
120
  ttl: float | timedelta | None = None,
121
121
  autocommit: bool = False,
122
- **kwargs,
122
+ **kwargs: Any,
123
123
  ) -> SQLConnection:
124
124
  pass
125
125
 
@@ -131,7 +131,7 @@ def connection_factory(
131
131
  max_entries: int | None = None,
132
132
  ttl: float | timedelta | None = None,
133
133
  autocommit: bool = False,
134
- **kwargs,
134
+ **kwargs: Any,
135
135
  ) -> SQLConnection:
136
136
  pass
137
137
 
@@ -142,7 +142,7 @@ def connection_factory(
142
142
  max_entries: int | None = None,
143
143
  ttl: float | timedelta | None = None,
144
144
  autocommit: bool = False,
145
- **kwargs,
145
+ **kwargs: Any,
146
146
  ) -> SnowflakeConnection:
147
147
  pass
148
148
 
@@ -154,7 +154,7 @@ def connection_factory(
154
154
  max_entries: int | None = None,
155
155
  ttl: float | timedelta | None = None,
156
156
  autocommit: bool = False,
157
- **kwargs,
157
+ **kwargs: Any,
158
158
  ) -> SnowflakeConnection:
159
159
  pass
160
160
 
@@ -164,7 +164,7 @@ def connection_factory(
164
164
  name: Literal["snowpark"],
165
165
  max_entries: int | None = None,
166
166
  ttl: float | timedelta | None = None,
167
- **kwargs,
167
+ **kwargs: Any,
168
168
  ) -> SnowparkConnection:
169
169
  pass
170
170
 
@@ -175,7 +175,7 @@ def connection_factory(
175
175
  type: Literal["snowpark"],
176
176
  max_entries: int | None = None,
177
177
  ttl: float | timedelta | None = None,
178
- **kwargs,
178
+ **kwargs: Any,
179
179
  ) -> SnowparkConnection:
180
180
  pass
181
181
 
@@ -186,7 +186,7 @@ def connection_factory(
186
186
  type: type[ConnectionClass],
187
187
  max_entries: int | None = None,
188
188
  ttl: float | timedelta | None = None,
189
- **kwargs,
189
+ **kwargs: Any,
190
190
  ) -> ConnectionClass:
191
191
  pass
192
192
 
@@ -197,7 +197,7 @@ def connection_factory(
197
197
  type: str | None = None,
198
198
  max_entries: int | None = None,
199
199
  ttl: float | timedelta | None = None,
200
- **kwargs,
200
+ **kwargs: Any,
201
201
  ) -> BaseConnection[Any]:
202
202
  pass
203
203
 
@@ -233,7 +233,7 @@ def connection_factory(
233
233
  The type of connection to create. This can be one of the following:
234
234
 
235
235
  - ``None`` (default): Streamlit will infer the connection type from
236
- ``name``. If the type is not inferrable from ``name``, the type must
236
+ ``name``. If the type is not inferable from ``name``, the type must
237
237
  be specified in ``secrets.toml`` instead.
238
238
  - ``"snowflake"``: Streamlit will initialize a connection with
239
239
  |SnowflakeConnection|_.
@@ -267,7 +267,7 @@ def connection_factory(
267
267
  **kwargs : any
268
268
  Connection-specific keyword arguments that are passed to the
269
269
  connection's ``._connect()`` method. ``**kwargs`` are typically
270
- combined with (and take precendence over) key-value pairs in
270
+ combined with (and take precedence over) key-value pairs in
271
271
  ``secrets.toml``. To learn more, see the specific connection's
272
272
  documentation.
273
273
 
@@ -370,7 +370,7 @@ def connection_factory(
370
370
 
371
371
  if name.startswith(USE_ENV_PREFIX):
372
372
  # It'd be nice to use str.removeprefix() here, but we won't be able to do that
373
- # until the minimium Python version we support is 3.9.
373
+ # until the minimum Python version we support is 3.9.
374
374
  envvar_name = name[len(USE_ENV_PREFIX) :]
375
375
  name = os.environ[envvar_name]
376
376
 
@@ -64,7 +64,7 @@ def _normalize_header(name: str) -> str:
64
64
 
65
65
 
66
66
  class StreamlitHeaders(Mapping[str, str]):
67
- def __init__(self, headers: Iterable[tuple[str, str]]):
67
+ def __init__(self, headers: Iterable[tuple[str, str]]) -> None:
68
68
  dict_like_headers: dict[str, list[str]] = {}
69
69
 
70
70
  for key, value in headers:
@@ -98,7 +98,7 @@ class StreamlitHeaders(Mapping[str, str]):
98
98
 
99
99
 
100
100
  class StreamlitCookies(Mapping[str, str]):
101
- def __init__(self, cookies: Mapping[str, str]):
101
+ def __init__(self, cookies: Mapping[str, str]) -> None:
102
102
  self._cookies = MappingProxyType(cookies)
103
103
 
104
104
  @classmethod