streamlit-nightly 1.45.2.dev20250527__py3-none-any.whl → 1.45.2.dev20250528__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 (129) hide show
  1. streamlit/auth_util.py +3 -3
  2. streamlit/commands/echo.py +1 -1
  3. streamlit/config.py +14 -12
  4. streamlit/config_option.py +3 -5
  5. streamlit/config_util.py +4 -5
  6. streamlit/connections/snowflake_connection.py +4 -3
  7. streamlit/elements/arrow.py +1 -0
  8. streamlit/elements/deck_gl_json_chart.py +1 -0
  9. streamlit/elements/exception.py +4 -12
  10. streamlit/elements/graphviz_chart.py +1 -1
  11. streamlit/elements/heading.py +3 -4
  12. streamlit/elements/lib/image_utils.py +2 -3
  13. streamlit/elements/lib/streamlit_plotly_theme.py +54 -53
  14. streamlit/elements/lib/utils.py +15 -0
  15. streamlit/elements/markdown.py +1 -1
  16. streamlit/elements/media.py +1 -1
  17. streamlit/elements/plotly_chart.py +1 -0
  18. streamlit/elements/progress.py +3 -3
  19. streamlit/elements/spinner.py +5 -4
  20. streamlit/elements/vega_charts.py +1 -0
  21. streamlit/elements/widgets/audio_input.py +1 -0
  22. streamlit/elements/widgets/button.py +3 -1
  23. streamlit/elements/widgets/button_group.py +1 -0
  24. streamlit/elements/widgets/camera_input.py +1 -0
  25. streamlit/elements/widgets/chat.py +2 -1
  26. streamlit/elements/widgets/checkbox.py +1 -0
  27. streamlit/elements/widgets/color_picker.py +9 -14
  28. streamlit/elements/widgets/data_editor.py +3 -2
  29. streamlit/elements/widgets/file_uploader.py +1 -0
  30. streamlit/elements/widgets/multiselect.py +1 -0
  31. streamlit/elements/widgets/number_input.py +1 -0
  32. streamlit/elements/widgets/radio.py +2 -1
  33. streamlit/elements/widgets/select_slider.py +1 -0
  34. streamlit/elements/widgets/selectbox.py +2 -1
  35. streamlit/elements/widgets/slider.py +25 -32
  36. streamlit/elements/widgets/text_widgets.py +3 -2
  37. streamlit/elements/widgets/time_widgets.py +2 -0
  38. streamlit/hello/animation_demo.py +9 -9
  39. streamlit/hello/dataframe_demo.py +2 -2
  40. streamlit/hello/mapping_demo.py +5 -6
  41. streamlit/logger.py +1 -1
  42. streamlit/runtime/app_session.py +11 -8
  43. streamlit/runtime/caching/hashing.py +8 -9
  44. streamlit/runtime/caching/storage/local_disk_cache_storage.py +3 -3
  45. streamlit/runtime/connection_factory.py +12 -12
  46. streamlit/runtime/credentials.py +13 -26
  47. streamlit/runtime/runtime_util.py +2 -2
  48. streamlit/runtime/scriptrunner/script_runner.py +8 -7
  49. streamlit/static/index.html +1 -1
  50. streamlit/static/static/js/{ErrorOutline.esm.qteVcUUN.js → ErrorOutline.esm.CtshIbC5.js} +1 -1
  51. streamlit/static/static/js/{FileDownload.esm.ncu7N-Hr.js → FileDownload.esm.A0XrMp_A.js} +1 -1
  52. streamlit/static/static/js/{FileHelper.zsMZ7RXt.js → FileHelper.BkYmOfR4.js} +1 -1
  53. streamlit/static/static/js/{FormClearHelper.W8yVYXZp.js → FormClearHelper.DvUrjO5s.js} +1 -1
  54. streamlit/static/static/js/{Hooks.DBj6srQ1.js → Hooks.Dw0PPeMp.js} +1 -1
  55. streamlit/static/static/js/{InputInstructions.BobLsJJb.js → InputInstructions.BwkpOG-3.js} +1 -1
  56. streamlit/static/static/js/{ProgressBar.CtvJrIzN.js → ProgressBar.Po8toa5U.js} +1 -1
  57. streamlit/static/static/js/{RenderInPortalIfExists.DnT_UdzV.js → RenderInPortalIfExists.DG7izwhP.js} +1 -1
  58. streamlit/static/static/js/{Toolbar.BVF7NtOB.js → Toolbar.zoRxypF9.js} +1 -1
  59. streamlit/static/static/js/{base-input.B4sdS3vw.js → base-input.3hmq5vR4.js} +1 -1
  60. streamlit/static/static/js/{checkbox.DKDitzF8.js → checkbox.DHVebTBP.js} +1 -1
  61. streamlit/static/static/js/{createSuper.mhx956J9.js → createSuper.CCzF882j.js} +1 -1
  62. streamlit/static/static/js/{data-grid-overlay-editor.CmXS0PAX.js → data-grid-overlay-editor.CRIS0V5u.js} +1 -1
  63. streamlit/static/static/js/{downloader.Cnd9SuxG.js → downloader.DOuJ7F43.js} +1 -1
  64. streamlit/static/static/js/{es6.DM-pf09u.js → es6.BojNhy97.js} +2 -2
  65. streamlit/static/static/js/{iframeResizer.contentWindow.Gc5GAjZM.js → iframeResizer.contentWindow.CmN7IDO7.js} +1 -1
  66. streamlit/static/static/js/{index.WWYmGCrM.js → index.3HscCA0Q.js} +1 -1
  67. streamlit/static/static/js/{index.BV38yp5k.js → index.B0GUCtHl.js} +1 -1
  68. streamlit/static/static/js/{index.DdyZtGcg.js → index.B3Y99Usz.js} +1 -1
  69. streamlit/static/static/js/{index.DIyx-z1Q.js → index.B6guKn0h.js} +1 -1
  70. streamlit/static/static/js/{index.CjBaoWYr.js → index.BEfxU01i.js} +1 -1
  71. streamlit/static/static/js/{index.BfusYuD8.js → index.BMWx_YQD.js} +1 -1
  72. streamlit/static/static/js/{index.BWTBe3a1.js → index.BV-8GugV.js} +1 -1
  73. streamlit/static/static/js/{index.gBOr8z2K.js → index.BXfm7UZe.js} +1 -1
  74. streamlit/static/static/js/{index.CWgnk1N4.js → index.BfcdLS9y.js} +1 -1
  75. streamlit/static/static/js/{index.COBionvf.js → index.BgmEuudT.js} +1 -1
  76. streamlit/static/static/js/{index.DQGSbu2C.js → index.BsiojTxz.js} +1 -1
  77. streamlit/static/static/js/{index.I3iNnzJx.js → index.BvWDoWjf.js} +1 -1
  78. streamlit/static/static/js/{index.p2Wl4zMi.js → index.CLFnBokZ.js} +1 -1
  79. streamlit/static/static/js/{index.DOl-SOKu.js → index.CPiByGGr.js} +1 -1
  80. streamlit/static/static/js/{index.C_2m4F7k.js → index.CTVSiPCo.js} +1 -1
  81. streamlit/static/static/js/{index.DTU7qmDP.js → index.CVxkW_lc.js} +1 -1
  82. streamlit/static/static/js/{index.BkLkRTpZ.js → index.CWweAMBx.js} +1 -1
  83. streamlit/static/static/js/{index.BR-S54Iv.js → index.CZ6f-p0K.js} +1 -1
  84. streamlit/static/static/js/{index.B45ExNhw.js → index.CdgLDqMc.js} +1 -1
  85. streamlit/static/static/js/{index.DAvhwYMG.js → index.Cpz3pp0B.js} +1 -1
  86. streamlit/static/static/js/{index.CJ-XXd1r.js → index.CzMgwzgb.js} +1 -1
  87. streamlit/static/static/js/{index.DOYomqqU.js → index.DH2YAEv6.js} +1 -1
  88. streamlit/static/static/js/{index.B0E6Rv1F.js → index.DNlMgaSP.js} +1 -1
  89. streamlit/static/static/js/{index.CgOynO1t.js → index.DP7RHJHC.js} +1 -1
  90. streamlit/static/static/js/{index.B29JQLHa.js → index.DcLQo3NB.js} +5 -5
  91. streamlit/static/static/js/{index.BJQNG4O1.js → index.DkNaEiLi.js} +1 -1
  92. streamlit/static/static/js/{index.BONHiJUZ.js → index.DtpZrdsz.js} +1 -1
  93. streamlit/static/static/js/{index.AWkO-7e-.js → index.HdiDLe37.js} +1 -1
  94. streamlit/static/static/js/{index.B6xTo8b8.js → index.Ih0EXMso.js} +1 -1
  95. streamlit/static/static/js/{index.vOqxh1m2.js → index.R5J-UXhx.js} +1 -1
  96. streamlit/static/static/js/{index.D4XRYl23.js → index.VVmp3qV7.js} +1 -1
  97. streamlit/static/static/js/{index.DwUISpCs.js → index.YePOPnW6.js} +5 -5
  98. streamlit/static/static/js/{index.BNNR5Jmd.js → index.YtwVjbe-.js} +1 -1
  99. streamlit/static/static/js/{index._BaeK1t7.js → index.kWUcv9pK.js} +1 -1
  100. streamlit/static/static/js/{index.CkKptP1T.js → index.muQ-sA7D.js} +1 -1
  101. streamlit/static/static/js/{index.C5KKmyWy.js → index.p5qVS5RU.js} +1 -1
  102. streamlit/static/static/js/{index.CZ5fZcT5.js → index.whcmqOYZ.js} +1 -1
  103. streamlit/static/static/js/{input.BvD9DHLa.js → input.C95vVzrH.js} +1 -1
  104. streamlit/static/static/js/{memory.DCVB1HOm.js → memory.lfILky3m.js} +1 -1
  105. streamlit/static/static/js/{mergeWith.BqTORFAq.js → mergeWith.CdpKbzWl.js} +1 -1
  106. streamlit/static/static/js/{number-overlay-editor.VB_OvuPv.js → number-overlay-editor.D2TjUrKf.js} +1 -1
  107. streamlit/static/static/js/{possibleConstructorReturn.DhYxBDlj.js → possibleConstructorReturn.DQV58bYB.js} +1 -1
  108. streamlit/static/static/js/{sandbox.CoN7LRFk.js → sandbox.R1dhBCnm.js} +1 -1
  109. streamlit/static/static/js/{textarea.DkHpIjdT.js → textarea.t5D4QCw3.js} +1 -1
  110. streamlit/static/static/js/{timepicker.C8UIzYhf.js → timepicker.BI9iPIxz.js} +1 -1
  111. streamlit/static/static/js/{toConsumableArray.DXfr1fvT.js → toConsumableArray.COyXrPhy.js} +1 -1
  112. streamlit/static/static/js/{uniqueId.CgrMSBTb.js → uniqueId.CaWObuU_.js} +1 -1
  113. streamlit/static/static/js/{useBasicWidgetState.C-e-WEFS.js → useBasicWidgetState.Wd2TSACf.js} +1 -1
  114. streamlit/static/static/js/{useOnInputChange.CtRJhZD6.js → useOnInputChange.CUFXty-S.js} +1 -1
  115. streamlit/static/static/js/{withFullScreenWrapper.od0SAvAK.js → withFullScreenWrapper.wgkD5MeK.js} +1 -1
  116. streamlit/watcher/local_sources_watcher.py +1 -1
  117. streamlit/watcher/path_watcher.py +2 -3
  118. streamlit/web/bootstrap.py +1 -1
  119. streamlit/web/cli.py +5 -5
  120. streamlit/web/server/authlib_tornado_integration.py +3 -3
  121. streamlit/web/server/oauth_authlib_routes.py +4 -2
  122. streamlit/web/server/oidc_mixin.py +6 -5
  123. streamlit/web/server/server.py +1 -1
  124. {streamlit_nightly-1.45.2.dev20250527.dist-info → streamlit_nightly-1.45.2.dev20250528.dist-info}/METADATA +2 -2
  125. {streamlit_nightly-1.45.2.dev20250527.dist-info → streamlit_nightly-1.45.2.dev20250528.dist-info}/RECORD +129 -129
  126. {streamlit_nightly-1.45.2.dev20250527.data → streamlit_nightly-1.45.2.dev20250528.data}/scripts/streamlit.cmd +0 -0
  127. {streamlit_nightly-1.45.2.dev20250527.dist-info → streamlit_nightly-1.45.2.dev20250528.dist-info}/WHEEL +0 -0
  128. {streamlit_nightly-1.45.2.dev20250527.dist-info → streamlit_nightly-1.45.2.dev20250528.dist-info}/entry_points.txt +0 -0
  129. {streamlit_nightly-1.45.2.dev20250527.dist-info → streamlit_nightly-1.45.2.dev20250528.dist-info}/top_level.txt +0 -0
@@ -195,6 +195,7 @@ class ColorPickerMixin:
195
195
  "color_picker",
196
196
  user_key=key,
197
197
  form_id=current_form_id(self.dg),
198
+ dg=self.dg,
198
199
  label=label,
199
200
  value=str(value),
200
201
  help=help,
@@ -206,25 +207,19 @@ class ColorPickerMixin:
206
207
 
207
208
  # make sure the value is a string
208
209
  if not isinstance(value, str):
209
- raise StreamlitAPIException(
210
- """
211
- Color Picker Value has invalid type: %s. Expects a hex string
212
- like '#00FFAA' or '#000'.
213
- """
214
- % type(value).__name__
215
- )
210
+ raise StreamlitAPIException(f"""
211
+ Color Picker Value has invalid type: {type(value).__name__}. Expects a hex string
212
+ like '#00FFAA' or '#000'.
213
+ """)
216
214
 
217
215
  # validate the value and expects a hex string
218
216
  match = re.match(r"^#(?:[0-9a-fA-F]{3}){1,2}$", value)
219
217
 
220
218
  if not match:
221
- raise StreamlitAPIException(
222
- """
223
- '%s' is not a valid hex code for colors. Valid ones are like
224
- '#00FFAA' or '#000'.
225
- """
226
- % value
227
- )
219
+ raise StreamlitAPIException(f"""
220
+ '{value}' is not a valid hex code for colors. Valid ones are like
221
+ '#00FFAA' or '#000'.
222
+ """)
228
223
 
229
224
  color_picker_proto = ColorPickerProto()
230
225
  color_picker_proto.id = element_id
@@ -370,8 +370,8 @@ def _apply_row_additions(
370
370
  # Row cannot be added -> skip it and log a warning.
371
371
  _LOGGER.warning(
372
372
  "Cannot automatically add row for the index "
373
- f"of type {type(df.index).__name__} without an explicit index value. "
374
- "Row addition skipped."
373
+ "of type %s without an explicit index value. Row addition skipped.",
374
+ type(df.index).__name__,
375
375
  )
376
376
 
377
377
 
@@ -933,6 +933,7 @@ class DataEditorMixin:
933
933
  "data_editor",
934
934
  user_key=key,
935
935
  form_id=current_form_id(self.dg),
936
+ dg=self.dg,
936
937
  data=arrow_bytes,
937
938
  width=width,
938
939
  height=height,
@@ -441,6 +441,7 @@ class FileUploaderMixin:
441
441
  "file_uploader",
442
442
  user_key=key,
443
443
  form_id=current_form_id(self.dg),
444
+ dg=self.dg,
444
445
  label=label,
445
446
  type=type,
446
447
  accept_multiple_files=accept_multiple_files,
@@ -449,6 +449,7 @@ class MultiSelectMixin:
449
449
  widget_name,
450
450
  user_key=key,
451
451
  form_id=form_id,
452
+ dg=self.dg,
452
453
  label=label,
453
454
  options=formatted_options,
454
455
  default=default_values,
@@ -443,6 +443,7 @@ class NumberInputMixin:
443
443
  "number_input",
444
444
  user_key=key,
445
445
  form_id=current_form_id(self.dg),
446
+ dg=self.dg,
446
447
  label=label,
447
448
  min_value=min_value,
448
449
  max_value=max_value,
@@ -341,6 +341,7 @@ class RadioMixin:
341
341
  "radio",
342
342
  user_key=key,
343
343
  form_id=current_form_id(self.dg),
344
+ dg=self.dg,
344
345
  label=label,
345
346
  options=[str(format_func(option)) for option in opt],
346
347
  index=index,
@@ -351,7 +352,7 @@ class RadioMixin:
351
352
 
352
353
  if not isinstance(index, int) and index is not None:
353
354
  raise StreamlitAPIException(
354
- "Radio Value has invalid type: %s" % type(index).__name__
355
+ f"Radio Value has invalid type: {type(index).__name__}"
355
356
  )
356
357
 
357
358
  if index is not None and len(opt) > 0 and not 0 <= index < len(opt):
@@ -370,6 +370,7 @@ class SelectSliderMixin:
370
370
  "select_slider",
371
371
  user_key=key,
372
372
  form_id=current_form_id(self.dg),
373
+ dg=self.dg,
373
374
  label=label,
374
375
  options=[str(format_func(option)) for option in opt],
375
376
  value=slider_value,
@@ -495,7 +495,7 @@ class SelectboxMixin:
495
495
 
496
496
  if not isinstance(index, int) and index is not None:
497
497
  raise StreamlitAPIException(
498
- "Selectbox Value has invalid type: %s" % type(index).__name__
498
+ f"Selectbox Value has invalid type: {type(index).__name__}"
499
499
  )
500
500
 
501
501
  if index is not None and len(opt) > 0 and not 0 <= index < len(opt):
@@ -519,6 +519,7 @@ class SelectboxMixin:
519
519
  "selectbox",
520
520
  user_key=key,
521
521
  form_id=current_form_id(self.dg),
522
+ dg=self.dg,
522
523
  label=label,
523
524
  options=formatted_options,
524
525
  index=index,
@@ -118,6 +118,15 @@ DAYS_TO_MICROS: Final = 24 * 60 * 60 * SECONDS_TO_MICROS
118
118
 
119
119
  UTC_EPOCH: Final = datetime(1970, 1, 1, tzinfo=timezone.utc)
120
120
 
121
+ SUPPORTED_TYPES: Final = {
122
+ Integral: SliderProto.INT,
123
+ Real: SliderProto.FLOAT,
124
+ datetime: SliderProto.DATETIME,
125
+ date: SliderProto.DATE,
126
+ time: SliderProto.TIME,
127
+ }
128
+ TIMELIKE_TYPES: Final = (SliderProto.DATETIME, SliderProto.TIME, SliderProto.DATE)
129
+
121
130
 
122
131
  def _time_to_datetime(time_: time) -> datetime:
123
132
  # Note, here we pick an arbitrary date well after Unix epoch.
@@ -665,6 +674,7 @@ class SliderMixin:
665
674
  "slider",
666
675
  user_key=key,
667
676
  form_id=current_form_id(self.dg),
677
+ dg=self.dg,
668
678
  label=label,
669
679
  min_value=min_value,
670
680
  max_value=max_value,
@@ -675,15 +685,6 @@ class SliderMixin:
675
685
  width=width,
676
686
  )
677
687
 
678
- SUPPORTED_TYPES = {
679
- Integral: SliderProto.INT,
680
- Real: SliderProto.FLOAT,
681
- datetime: SliderProto.DATETIME,
682
- date: SliderProto.DATE,
683
- time: SliderProto.TIME,
684
- }
685
- TIMELIKE_TYPES = (SliderProto.DATETIME, SliderProto.TIME, SliderProto.DATE)
686
-
687
688
  if value is None:
688
689
  # We need to know if this is a single or range slider, but don't have
689
690
  # a default value, so we check if session_state can tell us.
@@ -747,7 +748,7 @@ class SliderMixin:
747
748
  datetime_min = value[0] - timedelta(days=14)
748
749
  datetime_max = value[0] + timedelta(days=14)
749
750
 
750
- DEFAULTS = {
751
+ defaults: Final = {
751
752
  SliderProto.INT: {
752
753
  "min_value": 0,
753
754
  "max_value": 100,
@@ -781,18 +782,18 @@ class SliderMixin:
781
782
  }
782
783
 
783
784
  if min_value is None:
784
- min_value = DEFAULTS[data_type]["min_value"]
785
+ min_value = defaults[data_type]["min_value"]
785
786
  if max_value is None:
786
- max_value = DEFAULTS[data_type]["max_value"]
787
+ max_value = defaults[data_type]["max_value"]
787
788
  if step is None:
788
- step = DEFAULTS[data_type]["step"]
789
+ step = defaults[data_type]["step"]
789
790
  if data_type in (
790
791
  SliderProto.DATETIME,
791
792
  SliderProto.DATE,
792
793
  ) and max_value - min_value < timedelta(days=1):
793
794
  step = timedelta(minutes=15)
794
795
  if format is None:
795
- format = cast("str", DEFAULTS[data_type]["format"]) # noqa: A001
796
+ format = cast("str", defaults[data_type]["format"]) # noqa: A001
796
797
 
797
798
  if step == 0:
798
799
  raise StreamlitAPIException(
@@ -813,17 +814,13 @@ class SliderMixin:
813
814
  )
814
815
 
815
816
  if not int_args and not float_args and not timelike_args:
816
- raise StreamlitAPIException(
817
+ msg = (
817
818
  "Slider value arguments must be of matching types."
818
- "\n`min_value` has %(min_type)s type."
819
- "\n`max_value` has %(max_type)s type."
820
- "\n`step` has %(step)s type."
821
- % {
822
- "min_type": type(min_value).__name__,
823
- "max_type": type(max_value).__name__,
824
- "step": type(step).__name__,
825
- }
819
+ f"\n`min_value` has {type(min_value).__name__} type."
820
+ f"\n`max_value` has {type(max_value).__name__} type."
821
+ f"\n`step` has {type(step).__name__} type."
826
822
  )
823
+ raise StreamlitAPIException(msg)
827
824
 
828
825
  # Ensure that the value matches arguments' types.
829
826
  all_ints = data_type == SliderProto.INT and int_args
@@ -831,17 +828,13 @@ class SliderMixin:
831
828
  all_timelikes = data_type in TIMELIKE_TYPES and timelike_args
832
829
 
833
830
  if not all_ints and not all_floats and not all_timelikes:
834
- raise StreamlitAPIException(
831
+ msg = (
835
832
  "Both value and arguments must be of the same type."
836
- "\n`value` has %(value_type)s type."
837
- "\n`min_value` has %(min_type)s type."
838
- "\n`max_value` has %(max_type)s type."
839
- % {
840
- "value_type": type(value).__name__,
841
- "min_type": type(min_value).__name__,
842
- "max_type": type(max_value).__name__,
843
- }
833
+ f"\n`value` has {type(value).__name__} type."
834
+ f"\n`min_value` has {type(min_value).__name__} type."
835
+ f"\n`max_value` has {type(max_value).__name__} type."
844
836
  )
837
+ raise StreamlitAPIException(msg)
845
838
 
846
839
  # Ensure that min <= value(s) <= max, adjusting the bounds as necessary.
847
840
  min_value = min(min_value, max_value)
@@ -317,6 +317,7 @@ class TextWidgetsMixin:
317
317
  "text_input",
318
318
  user_key=key,
319
319
  form_id=current_form_id(self.dg),
320
+ dg=self.dg,
320
321
  label=label,
321
322
  value=value,
322
323
  max_chars=max_chars,
@@ -369,8 +370,7 @@ class TextWidgetsMixin:
369
370
  text_input_proto.type = TextInputProto.PASSWORD
370
371
  else:
371
372
  raise StreamlitAPIException(
372
- "'%s' is not a valid text_input type. Valid types are 'default' and 'password'."
373
- % type
373
+ f"'{type}' is not a valid text_input type. Valid types are 'default' and 'password'."
374
374
  )
375
375
 
376
376
  # Marshall the autocomplete param. If unspecified, this will be
@@ -622,6 +622,7 @@ class TextWidgetsMixin:
622
622
  "text_area",
623
623
  user_key=key,
624
624
  form_id=current_form_id(self.dg),
625
+ dg=self.dg,
625
626
  label=label,
626
627
  value=value,
627
628
  height=height,
@@ -523,6 +523,7 @@ class TimeWidgetsMixin:
523
523
  "time_input",
524
524
  user_key=key,
525
525
  form_id=current_form_id(self.dg),
526
+ dg=self.dg,
526
527
  label=label,
527
528
  value=parsed_time if isinstance(value, (datetime, time)) else value,
528
529
  help=help,
@@ -909,6 +910,7 @@ class TimeWidgetsMixin:
909
910
  "date_input",
910
911
  user_key=key,
911
912
  form_id=current_form_id(self.dg),
913
+ dg=self.dg,
912
914
  label=label,
913
915
  value=parsed,
914
916
  min_value=parsed_min_date,
@@ -42,22 +42,22 @@ def animation_demo() -> None:
42
42
  for frame_num, a in enumerate(np.linspace(0.0, 4 * np.pi, 100)):
43
43
  # Here were setting value for these two elements.
44
44
  progress_bar.progress(frame_num)
45
- frame_text.text("Frame %i/100" % (frame_num + 1))
45
+ frame_text.text(f"Frame {frame_num + 1}/100")
46
46
 
47
47
  # Performing some fractal wizardry.
48
48
  c = separation * np.exp(1j * a)
49
- Z = np.tile(x, (n, 1)) + 1j * np.tile(y, (1, m))
50
- C = np.full((n, m), c)
51
- M: Any = np.full((n, m), True, dtype=bool)
52
- N = np.zeros((n, m))
49
+ z = np.tile(x, (n, 1)) + 1j * np.tile(y, (1, m))
50
+ c_matrix = np.full((n, m), c)
51
+ m_matrix: Any = np.full((n, m), True, dtype=bool)
52
+ n_matrix = np.zeros((n, m))
53
53
 
54
54
  for i in range(iterations):
55
- Z[M] = Z[M] * Z[M] + C[M]
56
- M[np.abs(Z) > 2] = False
57
- N[M] = i
55
+ z[m_matrix] = z[m_matrix] * z[m_matrix] + c_matrix[m_matrix]
56
+ m_matrix[np.abs(z) > 2] = False
57
+ n_matrix[m_matrix] = i
58
58
 
59
59
  # Update the image placeholder by calling the image() function on it.
60
- image.image(1.0 - (N / N.max()), use_container_width=True)
60
+ image.image(1.0 - (n_matrix / n_matrix.max()), use_container_width=True)
61
61
 
62
62
  # We clear elements by calling empty on them.
63
63
  progress_bar.empty()
@@ -24,8 +24,8 @@ from streamlit.hello.utils import show_code
24
24
  def data_frame_demo() -> None:
25
25
  @st.cache_data
26
26
  def get_un_data() -> pd.DataFrame:
27
- AWS_BUCKET_URL = "https://streamlit-demo-data.s3-us-west-2.amazonaws.com"
28
- df = pd.read_csv(AWS_BUCKET_URL + "/agri.csv.gz")
27
+ aws_bucket_url = "https://streamlit-demo-data.s3-us-west-2.amazonaws.com"
28
+ df = pd.read_csv(aws_bucket_url + "/agri.csv.gz")
29
29
  return df.set_index("Region")
30
30
 
31
31
  try:
@@ -26,12 +26,12 @@ def mapping_demo() -> None:
26
26
  def from_data_file(filename: str) -> pd.DataFrame:
27
27
  url = (
28
28
  "https://raw.githubusercontent.com/streamlit/"
29
- "example-data/master/hello/v1/%s" % filename
29
+ f"example-data/master/hello/v1/{filename}"
30
30
  )
31
31
  return pd.read_json(url)
32
32
 
33
33
  try:
34
- ALL_LAYERS = {
34
+ all_layers = {
35
35
  "Bike rentals": pdk.Layer(
36
36
  "HexagonLayer",
37
37
  data=from_data_file("bike_rental_stats.json"),
@@ -75,7 +75,7 @@ def mapping_demo() -> None:
75
75
  st.sidebar.subheader("Map layers")
76
76
  selected_layers = [
77
77
  layer
78
- for layer_name, layer in ALL_LAYERS.items()
78
+ for layer_name, layer in all_layers.items()
79
79
  if st.sidebar.checkbox(layer_name, True)
80
80
  ]
81
81
  if selected_layers:
@@ -95,11 +95,10 @@ def mapping_demo() -> None:
95
95
  st.error("Please choose at least one layer above.")
96
96
  except URLError as e:
97
97
  st.error(
98
- """
98
+ f"""
99
99
  **This demo requires internet access.**
100
- Connection error: %s
100
+ Connection error: {e.reason}
101
101
  """
102
- % e.reason
103
102
  )
104
103
 
105
104
 
streamlit/logger.py CHANGED
@@ -46,7 +46,7 @@ def set_log_level(level: str | int) -> None:
46
46
  elif level in {"DEBUG", logging.DEBUG}:
47
47
  log_level = logging.DEBUG
48
48
  else:
49
- msg = 'undefined log level "%s"' % level
49
+ msg = f'undefined log level "{level}"'
50
50
  logger.critical(msg)
51
51
  sys.exit(1)
52
52
 
@@ -375,8 +375,9 @@ class AppSession:
375
375
  # sometimes stays open.
376
376
  if fragment_id and not self._fragment_storage.contains(fragment_id):
377
377
  _LOGGER.info(
378
- f"The fragment with id {fragment_id} does not exist anymore - "
379
- "it might have been removed during a preceding full-app rerun."
378
+ "The fragment with id %s does not exist anymore - "
379
+ "it might have been removed during a preceding full-app rerun.",
380
+ fragment_id,
380
381
  )
381
382
  return
382
383
 
@@ -954,9 +955,10 @@ def _populate_theme_msg(msg: CustomThemeConfig, section: str = "theme") -> None:
954
955
  if base is not None:
955
956
  if base not in base_map:
956
957
  _LOGGER.warning(
957
- f'"{base}" is an invalid value for theme.base.'
958
- f" Allowed values include {list(base_map.keys())}."
959
- ' Setting theme.base to "light".'
958
+ '"%s" is an invalid value for theme.base. Allowed values include %s. '
959
+ 'Setting theme.base to "light".',
960
+ base,
961
+ list(base_map.keys()),
960
962
  )
961
963
  else:
962
964
  msg.base = base_map[base]
@@ -976,8 +978,8 @@ def _populate_theme_msg(msg: CustomThemeConfig, section: str = "theme") -> None:
976
978
  font_faces = json.loads(font_faces)
977
979
  except Exception as e:
978
980
  _LOGGER.warning(
979
- "Failed to parse the theme.fontFaces config option with json.loads: "
980
- f"{font_faces}.",
981
+ "Failed to parse the theme.fontFaces config option with json.loads: %s.",
982
+ font_faces,
981
983
  exc_info=e,
982
984
  )
983
985
  font_faces = None
@@ -988,7 +990,8 @@ def _populate_theme_msg(msg: CustomThemeConfig, section: str = "theme") -> None:
988
990
  msg.font_faces.append(ParseDict(font_face, FontFace()))
989
991
  except Exception as e: # noqa: PERF203
990
992
  _LOGGER.warning(
991
- f"Failed to parse the theme.fontFaces config option: {font_face}.",
993
+ "Failed to parse the theme.fontFaces config option: %s.",
994
+ font_face,
992
995
  exc_info=e,
993
996
  )
994
997
 
@@ -92,26 +92,25 @@ class UserHashError(StreamlitAPIException):
92
92
  args = self._get_error_message_args(orig_exc, cached_func)
93
93
 
94
94
  return (
95
- """
96
- %(orig_exception_desc)s
95
+ f"""
96
+ {args["orig_exception_desc"]}
97
97
 
98
- This error is likely due to a bug in %(hash_func_name)s, which is a
99
- user-defined hash function that was passed into the `%(cache_primitive)s` decorator of
100
- %(object_desc)s.
98
+ This error is likely due to a bug in {args["hash_func_name"]}, which is a
99
+ user-defined hash function that was passed into the `{args["cache_primitive"]}` decorator of
100
+ {args["object_desc"]}.
101
101
 
102
- %(hash_func_name)s failed when hashing an object of type
103
- `%(failed_obj_type_str)s`. If you don't know where that object is coming from,
102
+ {args["hash_func_name"]} failed when hashing an object of type
103
+ `{args["failed_obj_type_str"]}`. If you don't know where that object is coming from,
104
104
  try looking at the hash chain below for an object that you do recognize, then
105
105
  pass that to `hash_funcs` instead:
106
106
 
107
107
  ```
108
- %(hash_stack)s
108
+ {args["hash_stack"]}
109
109
  ```
110
110
 
111
111
  If you think this is actually a Streamlit bug, please
112
112
  [file a bug report here](https://github.com/streamlit/streamlit/issues/new/choose).
113
113
  """
114
- % args
115
114
  ).strip("\n")
116
115
 
117
116
  def _get_error_message_args(
@@ -109,9 +109,9 @@ class LocalDiskCacheStorageManager(CacheStorageManager):
109
109
  and not math.isinf(context.ttl_seconds)
110
110
  ):
111
111
  _LOGGER.warning(
112
- f"The cached function '{context.function_display_name}' has a TTL "
113
- "that will be ignored. Persistent cached functions currently don't "
114
- "support TTL."
112
+ "The cached function '%s' has a TTL that will be ignored. "
113
+ "Persistent cached functions currently don't support TTL.",
114
+ context.function_display_name,
115
115
  )
116
116
 
117
117
 
@@ -38,13 +38,13 @@ 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: Final[dict[str, type[BaseConnection[Any]]]] = {
41
+ _FIRST_PARTY_CONNECTIONS: Final[dict[str, type[BaseConnection[Any]]]] = {
42
42
  "snowflake": SnowflakeConnection,
43
43
  "snowpark": SnowparkConnection,
44
44
  "sql": SQLConnection,
45
45
  }
46
- MODULE_EXTRACTION_REGEX = re.compile(r"No module named \'(.+)\'")
47
- MODULES_TO_PYPI_PACKAGES: Final[dict[str, str]] = {
46
+ _MODULE_EXTRACTION_REGEX = re.compile(r"No module named \'(.+)\'")
47
+ _MODULES_TO_PYPI_PACKAGES: Final[dict[str, str]] = {
48
48
  "MySQLdb": "mysqlclient",
49
49
  "psycopg2": "psycopg2-binary",
50
50
  "sqlalchemy": "sqlalchemy",
@@ -52,6 +52,7 @@ MODULES_TO_PYPI_PACKAGES: Final[dict[str, str]] = {
52
52
  "snowflake.connector": "snowflake-connector-python",
53
53
  "snowflake.snowpark": "snowflake-snowpark-python",
54
54
  }
55
+ _USE_ENV_PREFIX: Final = "env:"
55
56
 
56
57
  # The BaseConnection bound is parameterized to `Any` below as subclasses of
57
58
  # BaseConnection are responsible for binding the type parameter of BaseConnection to a
@@ -104,12 +105,12 @@ def _create_connection(
104
105
 
105
106
 
106
107
  def _get_first_party_connection(connection_class: str) -> type[BaseConnection[Any]]:
107
- if connection_class in FIRST_PARTY_CONNECTIONS:
108
- return FIRST_PARTY_CONNECTIONS[connection_class]
108
+ if connection_class in _FIRST_PARTY_CONNECTIONS:
109
+ return _FIRST_PARTY_CONNECTIONS[connection_class]
109
110
 
110
111
  raise StreamlitAPIException(
111
112
  f"Invalid connection '{connection_class}'. "
112
- f"Supported connection classes: {FIRST_PARTY_CONNECTIONS}"
113
+ f"Supported connection classes: {_FIRST_PARTY_CONNECTIONS}"
113
114
  )
114
115
 
115
116
 
@@ -366,12 +367,11 @@ def connection_factory( # type: ignore
366
367
  >>> conn = st.connection("my_sql_connection", type=SQLConnection)
367
368
 
368
369
  """
369
- USE_ENV_PREFIX = "env:"
370
370
 
371
- if name.startswith(USE_ENV_PREFIX):
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
373
  # until the minimum Python version we support is 3.9.
374
- envvar_name = name[len(USE_ENV_PREFIX) :]
374
+ envvar_name = name[len(_USE_ENV_PREFIX) :]
375
375
  name = os.environ[envvar_name]
376
376
 
377
377
  # type is a nice kwarg name for the st.connection user but is annoying to work with
@@ -380,7 +380,7 @@ def connection_factory( # type: ignore
380
380
  connection_class = type
381
381
 
382
382
  if connection_class is None:
383
- if name in FIRST_PARTY_CONNECTIONS:
383
+ if name in _FIRST_PARTY_CONNECTIONS:
384
384
  # We allow users to simply write `st.connection("sql")` instead of
385
385
  # `st.connection("sql", type="sql")`.
386
386
  connection_class = _get_first_party_connection(name)
@@ -424,11 +424,11 @@ def connection_factory( # type: ignore
424
424
  return conn
425
425
  except ModuleNotFoundError as e:
426
426
  err_string = str(e)
427
- missing_module = re.search(MODULE_EXTRACTION_REGEX, err_string)
427
+ missing_module = re.search(_MODULE_EXTRACTION_REGEX, err_string)
428
428
 
429
429
  extra_info = "You may be missing a dependency required to use this connection."
430
430
  if missing_module:
431
- pypi_package = MODULES_TO_PYPI_PACKAGES.get(missing_module.group(1))
431
+ pypi_package = _MODULES_TO_PYPI_PACKAGES.get(missing_module.group(1))
432
432
  if pypi_package:
433
433
  extra_info = f"You need to install the '{pypi_package}' package to use this connection."
434
434
 
@@ -29,7 +29,7 @@ from streamlit.logger import get_logger
29
29
  _LOGGER: Final = get_logger(__name__)
30
30
 
31
31
 
32
- _CONFIG_FILE_PATH = (
32
+ _CONFIG_FILE_PATH: Final = (
33
33
  r"%userprofile%/.streamlit/config.toml"
34
34
  if env_util.IS_WINDOWS
35
35
  else "~/.streamlit/config.toml"
@@ -263,43 +263,30 @@ class Credentials:
263
263
  if self.activation.is_valid:
264
264
  self.save()
265
265
  # IMPORTANT: Break the text below at 80 chars.
266
- TELEMETRY_TEXT = """
267
- You can find our privacy policy at %(link)s
266
+ telemetry_text = f"""
267
+ You can find our privacy policy at {cli_util.style_for_cli("https://streamlit.io/privacy-policy", underline=True)}
268
268
 
269
269
  Summary:
270
270
  - This open source library collects usage statistics.
271
271
  - We cannot see and do not store information contained inside Streamlit apps,
272
272
  such as text, charts, images, etc.
273
273
  - Telemetry data is stored in servers in the United States.
274
- - If you'd like to opt out, add the following to %(config)s,
274
+ - If you'd like to opt out, add the following to {cli_util.style_for_cli(_CONFIG_FILE_PATH)},
275
275
  creating that file if necessary:
276
276
 
277
277
  [browser]
278
278
  gatherUsageStats = false
279
- """ % {
280
- "link": cli_util.style_for_cli(
281
- "https://streamlit.io/privacy-policy", underline=True
282
- ),
283
- "config": cli_util.style_for_cli(_CONFIG_FILE_PATH),
284
- }
285
-
286
- cli_util.print_to_cli(TELEMETRY_TEXT)
279
+ """
280
+
281
+ cli_util.print_to_cli(telemetry_text)
287
282
  if show_instructions:
288
283
  # IMPORTANT: Break the text below at 80 chars.
289
- INSTRUCTIONS_TEXT = """
290
- %(start)s
291
- %(prompt)s %(hello)s
292
- """ % {
293
- "start": cli_util.style_for_cli(
294
- "Get started by typing:", fg="blue", bold=True
295
- ),
296
- "prompt": cli_util.style_for_cli("$", fg="blue"),
297
- "hello": cli_util.style_for_cli(
298
- "streamlit hello", bold=True
299
- ),
300
- }
301
-
302
- cli_util.print_to_cli(INSTRUCTIONS_TEXT)
284
+ instructions_text = f"""
285
+ {cli_util.style_for_cli("Get started by typing:", fg="blue", bold=True)}
286
+ {cli_util.style_for_cli("$", fg="blue")} {cli_util.style_for_cli("streamlit hello", bold=True)}
287
+ """
288
+
289
+ cli_util.print_to_cli(instructions_text)
303
290
  activated = True
304
291
  else: # pragma: nocover
305
292
  _LOGGER.error("Please try again.")
@@ -79,8 +79,8 @@ def serialize_forward_msg(msg: ForwardMsg) -> bytes:
79
79
 
80
80
  msg_size_error = MessageSizeError(msg_str)
81
81
  _LOGGER.warning(
82
- "Websocket message size limit exceeded. "
83
- f"Showing error to the user: {msg_size_error}"
82
+ "Websocket message size limit exceeded. Showing error to the user: %s",
83
+ msg_size_error,
84
84
  )
85
85
  exception.marshall(msg.delta.new_element.exception, msg_size_error)
86
86
  # Deactivate caching for this error message: