streamlit-nightly 1.42.3.dev20250225__py2.py3-none-any.whl → 1.42.3.dev20250227__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. streamlit/commands/navigation.py +16 -4
  2. streamlit/commands/page_config.py +1 -2
  3. streamlit/config.py +11 -4
  4. streamlit/elements/widgets/button.py +5 -7
  5. streamlit/elements/widgets/chat.py +101 -18
  6. streamlit/elements/widgets/file_uploader.py +20 -10
  7. streamlit/errors.py +11 -9
  8. streamlit/navigation/page.py +2 -10
  9. streamlit/proto/ChatInput_pb2.py +6 -6
  10. streamlit/proto/ChatInput_pb2.pyi +5 -1
  11. streamlit/proto/ClientState_pb2.py +5 -3
  12. streamlit/proto/ClientState_pb2.pyi +29 -2
  13. streamlit/proto/ForwardMsg_pb2.py +12 -10
  14. streamlit/proto/NewSession_pb2.py +16 -16
  15. streamlit/proto/NewSession_pb2.pyi +9 -9
  16. streamlit/proto/PagesChanged_pb2.pyi +3 -1
  17. streamlit/runtime/app_session.py +6 -13
  18. streamlit/runtime/context.py +19 -0
  19. streamlit/runtime/pages_manager.py +61 -232
  20. streamlit/runtime/scriptrunner/script_runner.py +51 -2
  21. streamlit/runtime/scriptrunner_utils/script_requests.py +7 -1
  22. streamlit/runtime/scriptrunner_utils/script_run_context.py +5 -1
  23. streamlit/source_util.py +4 -90
  24. streamlit/static/index.html +1 -1
  25. streamlit/static/static/js/{FileDownload.esm.BlYgQAwd.js → FileDownload.esm.rdZtCw5-.js} +1 -1
  26. streamlit/static/static/js/FileHelper.BztOEKJy.js +5 -0
  27. streamlit/static/static/js/{FormClearHelper.B4WYSqDL.js → FormClearHelper.Drd1fMJc.js} +1 -1
  28. streamlit/static/static/js/{Hooks.BoeFlDaA.js → Hooks.DWd0hyk4.js} +1 -1
  29. streamlit/static/static/js/{InputInstructions.DiPa6u6x.js → InputInstructions.B7xrWTG0.js} +1 -1
  30. streamlit/static/static/js/{ProgressBar.B-iCNc1a.js → ProgressBar.CBgJiTH-.js} +1 -1
  31. streamlit/static/static/js/{RenderInPortalIfExists.DPgp77ia.js → RenderInPortalIfExists.US28tQOn.js} +1 -1
  32. streamlit/static/static/js/{Toolbar.9G2Er6_r.js → Toolbar.CAOt-xaL.js} +1 -1
  33. streamlit/static/static/js/{base-input.z22leTiB.js → base-input.CauNaJqr.js} +1 -1
  34. streamlit/static/static/js/{checkbox.DT5JbCKx.js → checkbox.ChzWCtre.js} +1 -1
  35. streamlit/static/static/js/{createSuper.9dngDO4F.js → createSuper.D_39RJB6.js} +1 -1
  36. streamlit/static/static/js/{data-grid-overlay-editor.DnBgrJEy.js → data-grid-overlay-editor.rIelkOVS.js} +1 -1
  37. streamlit/static/static/js/{downloader.BgiOz4Dy.js → downloader.Dz5I28nG.js} +1 -1
  38. streamlit/static/static/js/{es6.C2nbxS8x.js → es6.DwnEjMMn.js} +2 -2
  39. streamlit/static/static/js/{iframeResizer.contentWindow.XvWZp7Dg.js → iframeResizer.contentWindow.BRiRifwd.js} +1 -1
  40. streamlit/static/static/js/{index.DkwDCuk1.js → index.BE6MTF-B.js} +1 -1
  41. streamlit/static/static/js/{index.DMreumKF.js → index.BUdhIGhT.js} +1 -1
  42. streamlit/static/static/js/{index.Bgn4z-Mp.js → index.BWeYb5ES.js} +1 -1
  43. streamlit/static/static/js/{index.exPoJHIW.js → index.Bb4OB39A.js} +1 -1
  44. streamlit/static/static/js/{index.T5vKsEVA.js → index.BrAW6bFJ.js} +1 -1
  45. streamlit/static/static/js/{index.D5wciRNz.js → index.CAHGh74D.js} +1 -1
  46. streamlit/static/static/js/{index.CrNuA-BG.js → index.CBre8Aui.js} +1 -1
  47. streamlit/static/static/js/{index.CMvo7Iwl.js → index.CM12P2T1.js} +1 -1
  48. streamlit/static/static/js/{index.DZ_FHOJd.js → index.CO3dZWKG.js} +1 -1
  49. streamlit/static/static/js/{index.BFYGskaf.js → index.CUz1_nAm.js} +1 -1
  50. streamlit/static/static/js/{index.DTP3exjF.js → index.C_C365T5.js} +1 -1
  51. streamlit/static/static/js/{index.CAC6FyHh.js → index.CmYiLKNX.js} +1 -1
  52. streamlit/static/static/js/{index.bDDanN90.js → index.CoUzNoRf.js} +1 -1
  53. streamlit/static/static/js/{index.DcXXaGYK.js → index.Ct7MPsA3.js} +1 -1
  54. streamlit/static/static/js/{index.UrE-Phqy.js → index.D1K6NCBQ.js} +1 -1
  55. streamlit/static/static/js/{index.D9bqDCB_.js → index.D2xM-XzG.js} +1 -1
  56. streamlit/static/static/js/{index.BTK3gx3H.js → index.D9rv1PQ0.js} +1 -1
  57. streamlit/static/static/js/{index.BdtKHTgl.js → index.DIeegLbv.js} +1 -1
  58. streamlit/static/static/js/{index.pWHQEj0Q.js → index.DJvwxFLn.js} +1 -1
  59. streamlit/static/static/js/{index.CBoIJv6M.js → index.DKuQg2D4.js} +1 -1
  60. streamlit/static/static/js/{index.DjTdTgti.js → index.DWFLx6Tc.js} +11 -11
  61. streamlit/static/static/js/{index.DC6PJYZU.js → index.DYUhWSq6.js} +1 -1
  62. streamlit/static/static/js/{index.rECpAXqX.js → index.Db3jGJxa.js} +1 -1
  63. streamlit/static/static/js/{index.BDSGWkr0.js → index.DfNAkKAr.js} +145 -145
  64. streamlit/static/static/js/{index.C5bx6jEW.js → index.DgNQKEeQ.js} +1 -1
  65. streamlit/static/static/js/{index.BkyYp5Em.js → index.Dj91melR.js} +1 -1
  66. streamlit/static/static/js/{index.Hnms5TSS.js → index.DkKZlAsv.js} +1 -1
  67. streamlit/static/static/js/index.DkgVNhWs.js +1 -0
  68. streamlit/static/static/js/{index.D-9nQW74.js → index.Dzp8iBkF.js} +1 -1
  69. streamlit/static/static/js/index.LL2DLZZA.js +201 -0
  70. streamlit/static/static/js/index.ORHz8Y8P.js +4537 -0
  71. streamlit/static/static/js/{index.CBYIbEuv.js → index.V3Vj2d9m.js} +1 -1
  72. streamlit/static/static/js/{index.B5-iXfzx.js → index.YNWoT4uW.js} +1 -1
  73. streamlit/static/static/js/index.aL_kqyvR.js +1 -0
  74. streamlit/static/static/js/{index.JgS0whqe.js → index.fP6rBxlc.js} +1 -1
  75. streamlit/static/static/js/{index.BxYliQ9c.js → index.pvQjxG7y.js} +1 -1
  76. streamlit/static/static/js/{index.BNc20KTN.js → index.wxpL02VY.js} +1 -1
  77. streamlit/static/static/js/{input.mCBQrtCY.js → input.D_dn5-2t.js} +1 -1
  78. streamlit/static/static/js/{memory.Te_zHgq3.js → memory.pnMTtWQR.js} +1 -1
  79. streamlit/static/static/js/{mergeWith.Di9Yv3PE.js → mergeWith.CRrYodeI.js} +1 -1
  80. streamlit/static/static/js/{number-overlay-editor.Du6B2U8c.js → number-overlay-editor.C65GBS2P.js} +1 -1
  81. streamlit/static/static/js/{possibleConstructorReturn.DqqPe-iu.js → possibleConstructorReturn.BnQk7lq_.js} +1 -1
  82. streamlit/static/static/js/{sandbox.iqWXuowq.js → sandbox.CrxXt1li.js} +1 -1
  83. streamlit/static/static/js/{textarea.DUN7d2zN.js → textarea.DiFyO5JY.js} +1 -1
  84. streamlit/static/static/js/{timepicker.BkmEJ-b8.js → timepicker.B1Y7LIk4.js} +1 -1
  85. streamlit/static/static/js/{toConsumableArray.D4OFzlWy.js → toConsumableArray.BWpBUK-j.js} +1 -1
  86. streamlit/static/static/js/{uniqueId.6OlKTkzK.js → uniqueId.7ecIUkUs.js} +1 -1
  87. streamlit/static/static/js/{useBasicWidgetState.Btr3rzhN.js → useBasicWidgetState.deG0KPm0.js} +1 -1
  88. streamlit/static/static/js/{useOnInputChange.BM7LVpC-.js → useOnInputChange.CQ7sD7CO.js} +1 -1
  89. streamlit/static/static/js/{withFullScreenWrapper.BCTIo1o2.js → withFullScreenWrapper.D0wnBu3k.js} +1 -1
  90. streamlit/testing/v1/app_test.py +8 -10
  91. {streamlit_nightly-1.42.3.dev20250225.dist-info → streamlit_nightly-1.42.3.dev20250227.dist-info}/METADATA +1 -1
  92. {streamlit_nightly-1.42.3.dev20250225.dist-info → streamlit_nightly-1.42.3.dev20250227.dist-info}/RECORD +96 -96
  93. {streamlit_nightly-1.42.3.dev20250225.dist-info → streamlit_nightly-1.42.3.dev20250227.dist-info}/WHEEL +1 -1
  94. streamlit/static/static/js/FileHelper.Da-FUCX4.js +0 -5
  95. streamlit/static/static/js/index.BiPYzGZi.js +0 -1
  96. streamlit/static/static/js/index.DV46EgCO.js +0 -201
  97. streamlit/static/static/js/index.DyyHt_xV.js +0 -1
  98. streamlit/static/static/js/index.qC8qMz0q.js +0 -3865
  99. {streamlit_nightly-1.42.3.dev20250225.data → streamlit_nightly-1.42.3.dev20250227.data}/scripts/streamlit.cmd +0 -0
  100. {streamlit_nightly-1.42.3.dev20250225.dist-info → streamlit_nightly-1.42.3.dev20250227.dist-info}/entry_points.txt +0 -0
  101. {streamlit_nightly-1.42.3.dev20250225.dist-info → streamlit_nightly-1.42.3.dev20250227.dist-info}/top_level.txt +0 -0
@@ -16,7 +16,7 @@ from streamlit.proto import AppPage_pb2 as streamlit_dot_proto_dot_AppPage__pb2
16
16
  from streamlit.proto import SessionStatus_pb2 as streamlit_dot_proto_dot_SessionStatus__pb2
17
17
 
18
18
 
19
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n streamlit/proto/NewSession.proto\x1a\x1dstreamlit/proto/AppPage.proto\x1a#streamlit/proto/SessionStatus.proto\"\xa5\x02\n\nNewSession\x12\x1f\n\ninitialize\x18\x01 \x01(\x0b\x32\x0b.Initialize\x12\x15\n\rscript_run_id\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x18\n\x10main_script_path\x18\x04 \x01(\t\x12\x17\n\x06\x63onfig\x18\x06 \x01(\x0b\x32\x07.Config\x12(\n\x0c\x63ustom_theme\x18\x07 \x01(\x0b\x32\x12.CustomThemeConfig\x12\x1b\n\tapp_pages\x18\x08 \x03(\x0b\x32\x08.AppPage\x12\x18\n\x10page_script_hash\x18\t \x01(\t\x12\x1d\n\x15\x66ragment_ids_this_run\x18\n \x03(\t\x12\x18\n\x10main_script_hash\x18\x0b \x01(\tJ\x04\x08\x05\x10\x06\"\xba\x01\n\nInitialize\x12\x1c\n\tuser_info\x18\x01 \x01(\x0b\x32\t.UserInfo\x12*\n\x10\x65nvironment_info\x18\x03 \x01(\x0b\x32\x10.EnvironmentInfo\x12&\n\x0esession_status\x18\x04 \x01(\x0b\x32\x0e.SessionStatus\x12\x14\n\x0c\x63ommand_line\x18\x05 \x01(\t\x12\x12\n\nsession_id\x18\x06 \x01(\t\x12\x10\n\x08is_hello\x18\x07 \x01(\x08\"\x97\x02\n\x06\x43onfig\x12\x1a\n\x12gather_usage_stats\x18\x02 \x01(\x08\x12\x1e\n\x16max_cached_message_age\x18\x03 \x01(\x05\x12\x14\n\x0cmapbox_token\x18\x04 \x01(\t\x12\x19\n\x11\x61llow_run_on_save\x18\x05 \x01(\x08\x12\x14\n\x0chide_top_bar\x18\x06 \x01(\x08\x12\x18\n\x10hide_sidebar_nav\x18\x07 \x01(\x08\x12)\n\x0ctoolbar_mode\x18\x08 \x01(\x0e\x32\x13.Config.ToolbarMode\"?\n\x0bToolbarMode\x12\x08\n\x04\x41UTO\x10\x00\x12\r\n\tDEVELOPER\x10\x01\x12\n\n\x06VIEWER\x10\x02\x12\x0b\n\x07MINIMAL\x10\x03J\x04\x08\x01\x10\x02\"\xfc\x05\n\x11\x43ustomThemeConfig\x12\x15\n\rprimary_color\x18\x01 \x01(\t\x12\"\n\x1asecondary_background_color\x18\x02 \x01(\t\x12\x18\n\x10\x62\x61\x63kground_color\x18\x03 \x01(\t\x12\x12\n\ntext_color\x18\x04 \x01(\t\x12+\n\x04\x66ont\x18\x05 \x01(\x0e\x32\x1d.CustomThemeConfig.FontFamily\x12*\n\x04\x62\x61se\x18\x06 \x01(\x0e\x32\x1c.CustomThemeConfig.BaseTheme\x12\x1f\n\x17widget_background_color\x18\x07 \x01(\t\x12\x1b\n\x13widget_border_color\x18\x08 \x01(\t\x12\x15\n\x05radii\x18\t \x01(\x0b\x32\x06.Radii\x12\x11\n\tbody_font\x18\r \x01(\t\x12\x11\n\tcode_font\x18\x0e \x01(\t\x12\x1d\n\nfont_faces\x18\x0f \x03(\x0b\x32\t.FontFace\x12\x1e\n\nfont_sizes\x18\x10 \x01(\x0b\x32\n.FontSizes\x12!\n\x19skeleton_background_color\x18\x11 \x01(\t\x12\x16\n\troundness\x18\x12 \x01(\x02H\x00\x88\x01\x01\x12\x19\n\x0c\x62order_color\x18\x13 \x01(\tH\x01\x88\x01\x01\x12&\n\x19show_border_around_inputs\x18\x14 \x01(\x08H\x02\x88\x01\x01\x12\x17\n\nlink_color\x18\x15 \x01(\tH\x03\x88\x01\x01\x12\x1b\n\x0e\x62\x61se_font_size\x18\x16 \x01(\x05H\x04\x88\x01\x01\" \n\tBaseTheme\x12\t\n\x05LIGHT\x10\x00\x12\x08\n\x04\x44\x41RK\x10\x01\"6\n\nFontFamily\x12\x0e\n\nSANS_SERIF\x10\x00\x12\t\n\x05SERIF\x10\x01\x12\r\n\tMONOSPACE\x10\x02\x42\x0c\n\n_roundnessB\x0f\n\r_border_colorB\x1c\n\x1a_show_border_around_inputsB\r\n\x0b_link_colorB\x11\n\x0f_base_font_size\"F\n\x08\x46ontFace\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x0e\n\x06\x66\x61mily\x18\x02 \x01(\t\x12\x0e\n\x06weight\x18\x03 \x01(\x05\x12\r\n\x05style\x18\x04 \x01(\t\"<\n\x05Radii\x12\x1a\n\x12\x62\x61se_widget_radius\x18\x01 \x01(\x05\x12\x17\n\x0f\x63heckbox_radius\x18\x02 \x01(\x05\"T\n\tFontSizes\x12\x16\n\x0etiny_font_size\x18\x01 \x01(\x05\x12\x17\n\x0fsmall_font_size\x18\x02 \x01(\x05\x12\x16\n\x0e\x62\x61se_font_size\x18\x03 \x01(\x05\"E\n\x08UserInfo\x12\x17\n\x0finstallation_id\x18\x01 \x01(\t\x12\x1a\n\x12installation_id_v3\x18\x05 \x01(\tJ\x04\x08\x02\x10\x03\"D\n\x0f\x45nvironmentInfo\x12\x19\n\x11streamlit_version\x18\x01 \x01(\t\x12\x16\n\x0epython_version\x18\x02 \x01(\tB/\n\x1c\x63om.snowflake.apps.streamlitB\x0fNewSessionProtob\x06proto3')
19
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n streamlit/proto/NewSession.proto\x1a\x1dstreamlit/proto/AppPage.proto\x1a#streamlit/proto/SessionStatus.proto\"\xa5\x02\n\nNewSession\x12\x1f\n\ninitialize\x18\x01 \x01(\x0b\x32\x0b.Initialize\x12\x15\n\rscript_run_id\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x18\n\x10main_script_path\x18\x04 \x01(\t\x12\x17\n\x06\x63onfig\x18\x06 \x01(\x0b\x32\x07.Config\x12(\n\x0c\x63ustom_theme\x18\x07 \x01(\x0b\x32\x12.CustomThemeConfig\x12\x1b\n\tapp_pages\x18\x08 \x03(\x0b\x32\x08.AppPage\x12\x18\n\x10page_script_hash\x18\t \x01(\t\x12\x1d\n\x15\x66ragment_ids_this_run\x18\n \x03(\t\x12\x18\n\x10main_script_hash\x18\x0b \x01(\tJ\x04\x08\x05\x10\x06\"\xba\x01\n\nInitialize\x12\x1c\n\tuser_info\x18\x01 \x01(\x0b\x32\t.UserInfo\x12*\n\x10\x65nvironment_info\x18\x03 \x01(\x0b\x32\x10.EnvironmentInfo\x12&\n\x0esession_status\x18\x04 \x01(\x0b\x32\x0e.SessionStatus\x12\x14\n\x0c\x63ommand_line\x18\x05 \x01(\t\x12\x12\n\nsession_id\x18\x06 \x01(\t\x12\x10\n\x08is_hello\x18\x07 \x01(\x08\"\x97\x02\n\x06\x43onfig\x12\x1a\n\x12gather_usage_stats\x18\x02 \x01(\x08\x12\x1e\n\x16max_cached_message_age\x18\x03 \x01(\x05\x12\x14\n\x0cmapbox_token\x18\x04 \x01(\t\x12\x19\n\x11\x61llow_run_on_save\x18\x05 \x01(\x08\x12\x14\n\x0chide_top_bar\x18\x06 \x01(\x08\x12\x18\n\x10hide_sidebar_nav\x18\x07 \x01(\x08\x12)\n\x0ctoolbar_mode\x18\x08 \x01(\x0e\x32\x13.Config.ToolbarMode\"?\n\x0bToolbarMode\x12\x08\n\x04\x41UTO\x10\x00\x12\r\n\tDEVELOPER\x10\x01\x12\n\n\x06VIEWER\x10\x02\x12\x0b\n\x07MINIMAL\x10\x03J\x04\x08\x01\x10\x02\"\x80\x06\n\x11\x43ustomThemeConfig\x12\x15\n\rprimary_color\x18\x01 \x01(\t\x12\"\n\x1asecondary_background_color\x18\x02 \x01(\t\x12\x18\n\x10\x62\x61\x63kground_color\x18\x03 \x01(\t\x12\x12\n\ntext_color\x18\x04 \x01(\t\x12+\n\x04\x66ont\x18\x05 \x01(\x0e\x32\x1d.CustomThemeConfig.FontFamily\x12*\n\x04\x62\x61se\x18\x06 \x01(\x0e\x32\x1c.CustomThemeConfig.BaseTheme\x12\x1f\n\x17widget_background_color\x18\x07 \x01(\t\x12\x1b\n\x13widget_border_color\x18\x08 \x01(\t\x12\x15\n\x05radii\x18\t \x01(\x0b\x32\x06.Radii\x12\x11\n\tbody_font\x18\r \x01(\t\x12\x11\n\tcode_font\x18\x0e \x01(\t\x12\x1d\n\nfont_faces\x18\x0f \x03(\x0b\x32\t.FontFace\x12\x1e\n\nfont_sizes\x18\x10 \x01(\x0b\x32\n.FontSizes\x12!\n\x19skeleton_background_color\x18\x11 \x01(\t\x12\x18\n\x0b\x62\x61se_radius\x18\x12 \x01(\tH\x00\x88\x01\x01\x12\x19\n\x0c\x62order_color\x18\x13 \x01(\tH\x01\x88\x01\x01\x12&\n\x19show_border_around_inputs\x18\x14 \x01(\x08H\x02\x88\x01\x01\x12\x17\n\nlink_color\x18\x15 \x01(\tH\x03\x88\x01\x01\x12\x1b\n\x0e\x62\x61se_font_size\x18\x16 \x01(\x05H\x04\x88\x01\x01\" \n\tBaseTheme\x12\t\n\x05LIGHT\x10\x00\x12\x08\n\x04\x44\x41RK\x10\x01\"6\n\nFontFamily\x12\x0e\n\nSANS_SERIF\x10\x00\x12\t\n\x05SERIF\x10\x01\x12\r\n\tMONOSPACE\x10\x02\x42\x0e\n\x0c_base_radiusB\x0f\n\r_border_colorB\x1c\n\x1a_show_border_around_inputsB\r\n\x0b_link_colorB\x11\n\x0f_base_font_size\"F\n\x08\x46ontFace\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x0e\n\x06\x66\x61mily\x18\x02 \x01(\t\x12\x0e\n\x06weight\x18\x03 \x01(\x05\x12\r\n\x05style\x18\x04 \x01(\t\"<\n\x05Radii\x12\x1a\n\x12\x62\x61se_widget_radius\x18\x01 \x01(\x05\x12\x17\n\x0f\x63heckbox_radius\x18\x02 \x01(\x05\"T\n\tFontSizes\x12\x16\n\x0etiny_font_size\x18\x01 \x01(\x05\x12\x17\n\x0fsmall_font_size\x18\x02 \x01(\x05\x12\x16\n\x0e\x62\x61se_font_size\x18\x03 \x01(\x05\"E\n\x08UserInfo\x12\x17\n\x0finstallation_id\x18\x01 \x01(\t\x12\x1a\n\x12installation_id_v3\x18\x05 \x01(\tJ\x04\x08\x02\x10\x03\"D\n\x0f\x45nvironmentInfo\x12\x19\n\x11streamlit_version\x18\x01 \x01(\t\x12\x16\n\x0epython_version\x18\x02 \x01(\tB/\n\x1c\x63om.snowflake.apps.streamlitB\x0fNewSessionProtob\x06proto3')
20
20
 
21
21
  _globals = globals()
22
22
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -33,19 +33,19 @@ if not _descriptor._USE_C_DESCRIPTORS:
33
33
  _globals['_CONFIG_TOOLBARMODE']._serialized_start=800
34
34
  _globals['_CONFIG_TOOLBARMODE']._serialized_end=863
35
35
  _globals['_CUSTOMTHEMECONFIG']._serialized_start=872
36
- _globals['_CUSTOMTHEMECONFIG']._serialized_end=1636
37
- _globals['_CUSTOMTHEMECONFIG_BASETHEME']._serialized_start=1453
38
- _globals['_CUSTOMTHEMECONFIG_BASETHEME']._serialized_end=1485
39
- _globals['_CUSTOMTHEMECONFIG_FONTFAMILY']._serialized_start=1487
40
- _globals['_CUSTOMTHEMECONFIG_FONTFAMILY']._serialized_end=1541
41
- _globals['_FONTFACE']._serialized_start=1638
42
- _globals['_FONTFACE']._serialized_end=1708
43
- _globals['_RADII']._serialized_start=1710
44
- _globals['_RADII']._serialized_end=1770
45
- _globals['_FONTSIZES']._serialized_start=1772
46
- _globals['_FONTSIZES']._serialized_end=1856
47
- _globals['_USERINFO']._serialized_start=1858
48
- _globals['_USERINFO']._serialized_end=1927
49
- _globals['_ENVIRONMENTINFO']._serialized_start=1929
50
- _globals['_ENVIRONMENTINFO']._serialized_end=1997
36
+ _globals['_CUSTOMTHEMECONFIG']._serialized_end=1640
37
+ _globals['_CUSTOMTHEMECONFIG_BASETHEME']._serialized_start=1455
38
+ _globals['_CUSTOMTHEMECONFIG_BASETHEME']._serialized_end=1487
39
+ _globals['_CUSTOMTHEMECONFIG_FONTFAMILY']._serialized_start=1489
40
+ _globals['_CUSTOMTHEMECONFIG_FONTFAMILY']._serialized_end=1543
41
+ _globals['_FONTFACE']._serialized_start=1642
42
+ _globals['_FONTFACE']._serialized_end=1712
43
+ _globals['_RADII']._serialized_start=1714
44
+ _globals['_RADII']._serialized_end=1774
45
+ _globals['_FONTSIZES']._serialized_start=1776
46
+ _globals['_FONTSIZES']._serialized_end=1860
47
+ _globals['_USERINFO']._serialized_start=1862
48
+ _globals['_USERINFO']._serialized_end=1931
49
+ _globals['_ENVIRONMENTINFO']._serialized_start=1933
50
+ _globals['_ENVIRONMENTINFO']._serialized_end=2001
51
51
  # @@protoc_insertion_point(module_scope)
@@ -283,7 +283,7 @@ class CustomThemeConfig(google.protobuf.message.Message):
283
283
  FONT_FACES_FIELD_NUMBER: builtins.int
284
284
  FONT_SIZES_FIELD_NUMBER: builtins.int
285
285
  SKELETON_BACKGROUND_COLOR_FIELD_NUMBER: builtins.int
286
- ROUNDNESS_FIELD_NUMBER: builtins.int
286
+ BASE_RADIUS_FIELD_NUMBER: builtins.int
287
287
  BORDER_COLOR_FIELD_NUMBER: builtins.int
288
288
  SHOW_BORDER_AROUND_INPUTS_FIELD_NUMBER: builtins.int
289
289
  LINK_COLOR_FIELD_NUMBER: builtins.int
@@ -303,14 +303,14 @@ class CustomThemeConfig(google.protobuf.message.Message):
303
303
  code_font: builtins.str
304
304
  skeleton_background_color: builtins.str
305
305
  """DEPRECATED: This color is not applied anymore:"""
306
- roundness: builtins.float
306
+ base_radius: builtins.str
307
307
  border_color: builtins.str
308
308
  show_border_around_inputs: builtins.bool
309
309
  link_color: builtins.str
310
310
  base_font_size: builtins.int
311
311
  @property
312
312
  def radii(self) -> global___Radii:
313
- """DEPRECATED: Please use the roundness theme config instead:"""
313
+ """DEPRECATED: Please use the base_radius theme config instead:"""
314
314
 
315
315
  @property
316
316
  def font_faces(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___FontFace]: ...
@@ -335,23 +335,23 @@ class CustomThemeConfig(google.protobuf.message.Message):
335
335
  font_faces: collections.abc.Iterable[global___FontFace] | None = ...,
336
336
  font_sizes: global___FontSizes | None = ...,
337
337
  skeleton_background_color: builtins.str = ...,
338
- roundness: builtins.float | None = ...,
338
+ base_radius: builtins.str | None = ...,
339
339
  border_color: builtins.str | None = ...,
340
340
  show_border_around_inputs: builtins.bool | None = ...,
341
341
  link_color: builtins.str | None = ...,
342
342
  base_font_size: builtins.int | None = ...,
343
343
  ) -> None: ...
344
- def HasField(self, field_name: typing.Literal["_base_font_size", b"_base_font_size", "_border_color", b"_border_color", "_link_color", b"_link_color", "_roundness", b"_roundness", "_show_border_around_inputs", b"_show_border_around_inputs", "base_font_size", b"base_font_size", "border_color", b"border_color", "font_sizes", b"font_sizes", "link_color", b"link_color", "radii", b"radii", "roundness", b"roundness", "show_border_around_inputs", b"show_border_around_inputs"]) -> builtins.bool: ...
345
- def ClearField(self, field_name: typing.Literal["_base_font_size", b"_base_font_size", "_border_color", b"_border_color", "_link_color", b"_link_color", "_roundness", b"_roundness", "_show_border_around_inputs", b"_show_border_around_inputs", "background_color", b"background_color", "base", b"base", "base_font_size", b"base_font_size", "body_font", b"body_font", "border_color", b"border_color", "code_font", b"code_font", "font", b"font", "font_faces", b"font_faces", "font_sizes", b"font_sizes", "link_color", b"link_color", "primary_color", b"primary_color", "radii", b"radii", "roundness", b"roundness", "secondary_background_color", b"secondary_background_color", "show_border_around_inputs", b"show_border_around_inputs", "skeleton_background_color", b"skeleton_background_color", "text_color", b"text_color", "widget_background_color", b"widget_background_color", "widget_border_color", b"widget_border_color"]) -> None: ...
344
+ def HasField(self, field_name: typing.Literal["_base_font_size", b"_base_font_size", "_base_radius", b"_base_radius", "_border_color", b"_border_color", "_link_color", b"_link_color", "_show_border_around_inputs", b"_show_border_around_inputs", "base_font_size", b"base_font_size", "base_radius", b"base_radius", "border_color", b"border_color", "font_sizes", b"font_sizes", "link_color", b"link_color", "radii", b"radii", "show_border_around_inputs", b"show_border_around_inputs"]) -> builtins.bool: ...
345
+ def ClearField(self, field_name: typing.Literal["_base_font_size", b"_base_font_size", "_base_radius", b"_base_radius", "_border_color", b"_border_color", "_link_color", b"_link_color", "_show_border_around_inputs", b"_show_border_around_inputs", "background_color", b"background_color", "base", b"base", "base_font_size", b"base_font_size", "base_radius", b"base_radius", "body_font", b"body_font", "border_color", b"border_color", "code_font", b"code_font", "font", b"font", "font_faces", b"font_faces", "font_sizes", b"font_sizes", "link_color", b"link_color", "primary_color", b"primary_color", "radii", b"radii", "secondary_background_color", b"secondary_background_color", "show_border_around_inputs", b"show_border_around_inputs", "skeleton_background_color", b"skeleton_background_color", "text_color", b"text_color", "widget_background_color", b"widget_background_color", "widget_border_color", b"widget_border_color"]) -> None: ...
346
346
  @typing.overload
347
347
  def WhichOneof(self, oneof_group: typing.Literal["_base_font_size", b"_base_font_size"]) -> typing.Literal["base_font_size"] | None: ...
348
348
  @typing.overload
349
+ def WhichOneof(self, oneof_group: typing.Literal["_base_radius", b"_base_radius"]) -> typing.Literal["base_radius"] | None: ...
350
+ @typing.overload
349
351
  def WhichOneof(self, oneof_group: typing.Literal["_border_color", b"_border_color"]) -> typing.Literal["border_color"] | None: ...
350
352
  @typing.overload
351
353
  def WhichOneof(self, oneof_group: typing.Literal["_link_color", b"_link_color"]) -> typing.Literal["link_color"] | None: ...
352
354
  @typing.overload
353
- def WhichOneof(self, oneof_group: typing.Literal["_roundness", b"_roundness"]) -> typing.Literal["roundness"] | None: ...
354
- @typing.overload
355
355
  def WhichOneof(self, oneof_group: typing.Literal["_show_border_around_inputs", b"_show_border_around_inputs"]) -> typing.Literal["show_border_around_inputs"] | None: ...
356
356
 
357
357
  global___CustomThemeConfig = CustomThemeConfig
@@ -382,7 +382,7 @@ global___FontFace = FontFace
382
382
 
383
383
  @typing.final
384
384
  class Radii(google.protobuf.message.Message):
385
- """DEPRECATED: Please use the roundness theme config instead."""
385
+ """DEPRECATED: Please use the base_radius theme config instead."""
386
386
 
387
387
  DESCRIPTOR: google.protobuf.descriptor.Descriptor
388
388
 
@@ -29,7 +29,9 @@ DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
29
29
 
30
30
  @typing.final
31
31
  class PagesChanged(google.protobuf.message.Message):
32
- """Message used to tell the client that the app's pages have changed."""
32
+ """DEPRECATED - We don't use the proto anymore.
33
+ Message used to tell the client that the app's pages have changed.
34
+ """
33
35
 
34
36
  DESCRIPTOR: google.protobuf.descriptor.Descriptor
35
37
 
@@ -50,7 +50,6 @@ from streamlit.watcher import LocalSourcesWatcher
50
50
 
51
51
  if TYPE_CHECKING:
52
52
  from streamlit.proto.BackMsg_pb2 import BackMsg
53
- from streamlit.proto.PagesChanged_pb2 import PagesChanged
54
53
  from streamlit.runtime.script_data import ScriptData
55
54
  from streamlit.runtime.scriptrunner.script_cache import ScriptCache
56
55
  from streamlit.runtime.state import SessionState
@@ -200,9 +199,6 @@ class AppSession:
200
199
  self._stop_config_listener = config.on_config_parsed(
201
200
  self._on_source_file_changed, force_connect=True
202
201
  )
203
- self._stop_pages_listener = self._pages_manager.register_pages_changed_callback(
204
- self._on_pages_changed
205
- )
206
202
  secrets_singleton.file_change_listener.connect(self._on_secrets_file_changed)
207
203
 
208
204
  def disconnect_file_watchers(self) -> None:
@@ -353,6 +349,7 @@ class AppSession:
353
349
  to use previous client state.
354
350
 
355
351
  """
352
+
356
353
  if self._state == AppSessionState.SHUTDOWN_REQUESTED:
357
354
  _LOGGER.warning("Discarding rerun request after shutdown")
358
355
  return
@@ -382,6 +379,9 @@ class AppSession:
382
379
  )
383
380
  return
384
381
 
382
+ if client_state.HasField("context_info"):
383
+ self._client_state.context_info.CopyFrom(client_state.context_info)
384
+
385
385
  rerun_data = RerunData(
386
386
  client_state.query_string,
387
387
  client_state.widget_states,
@@ -389,6 +389,7 @@ class AppSession:
389
389
  client_state.page_name,
390
390
  fragment_id=fragment_id if fragment_id else None,
391
391
  is_auto_rerun=client_state.is_auto_rerun,
392
+ context_info=client_state.context_info,
392
393
  )
393
394
  else:
394
395
  rerun_data = RerunData()
@@ -489,14 +490,6 @@ class AppSession:
489
490
  # `_on_source_file_changed` just for this purpose sounded finicky.
490
491
  self._on_source_file_changed()
491
492
 
492
- def _on_pages_changed(self, _) -> None:
493
- msg = ForwardMsg()
494
- self._populate_app_pages(msg.pages_changed, self._pages_manager.get_pages())
495
- self._enqueue_forward_msg(msg)
496
-
497
- if self._local_sources_watcher is not None:
498
- self._local_sources_watcher.update_watched_pages()
499
-
500
493
  def _clear_queue(self, fragment_ids_this_run: list[str] | None = None) -> None:
501
494
  self._browser_queue.clear(
502
495
  retain_lifecycle_msgs=True, fragment_ids_this_run=fragment_ids_this_run
@@ -881,7 +874,7 @@ class AppSession:
881
874
  self._enqueue_forward_msg(msg)
882
875
 
883
876
  def _populate_app_pages(
884
- self, msg: NewSession | PagesChanged, pages: dict[PageHash, PageInfo]
877
+ self, msg: NewSession, pages: dict[PageHash, PageInfo]
885
878
  ) -> None:
886
879
  for page_script_hash, page_info in pages.items():
887
880
  page_proto = msg.app_pages.add()
@@ -205,3 +205,22 @@ class ContextProxy:
205
205
 
206
206
  cookies = session_client_request.cookies
207
207
  return StreamlitCookies.from_tornado_cookies(cookies)
208
+
209
+ @property
210
+ @gather_metrics("context.timezone")
211
+ def timezone(self) -> str | None:
212
+ """The timezone of the user's browser, read-only."""
213
+ ctx = get_script_run_ctx()
214
+
215
+ if ctx is None or ctx.context_info is None:
216
+ return None
217
+ return ctx.context_info.timezone
218
+
219
+ @property
220
+ @gather_metrics("context.timezone_offset")
221
+ def timezone_offset(self) -> int | None:
222
+ """The timezone offset of the user's browser, read-only."""
223
+ ctx = get_script_run_ctx()
224
+ if ctx is None or ctx.context_info is None:
225
+ return None
226
+ return ctx.context_info.timezone_offset
@@ -14,15 +14,11 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
- import os
18
- import threading
19
17
  from pathlib import Path
20
- from typing import TYPE_CHECKING, Any, Callable, Final
18
+ from typing import TYPE_CHECKING, Any, Final
21
19
 
22
- from streamlit import source_util
23
20
  from streamlit.logger import get_logger
24
21
  from streamlit.util import calc_md5
25
- from streamlit.watcher import watch_dir
26
22
 
27
23
  if TYPE_CHECKING:
28
24
  from streamlit.runtime.scriptrunner.script_cache import ScriptCache
@@ -31,198 +27,15 @@ if TYPE_CHECKING:
31
27
  _LOGGER: Final = get_logger(__name__)
32
28
 
33
29
 
34
- class PagesStrategyV1:
35
- """
36
- Strategy for MPA v1. This strategy handles pages being set directly
37
- by a call to `st.navigation`. The key differences here are:
38
- - The pages are defined by the existence of a `pages` directory
39
- - We will ensure one watcher is watching the scripts in the directory.
40
- - Only one script runs for a full rerun.
41
- - We know at the beginning the intended page script to run.
42
-
43
- NOTE: Thread safety of the pages is handled by the source_util module
44
- """
45
-
46
- is_watching_pages_dir: bool = False
47
- pages_watcher_lock = threading.Lock()
48
-
49
- # This is a static method because we only want to watch the pages directory
50
- # once on initial load.
51
- @staticmethod
52
- def watch_pages_dir(pages_manager: PagesManager):
53
- with PagesStrategyV1.pages_watcher_lock:
54
- if PagesStrategyV1.is_watching_pages_dir:
55
- return
56
-
57
- def _handle_page_changed(_path: str) -> None:
58
- source_util.invalidate_pages_cache()
59
-
60
- pages_dir = pages_manager.main_script_parent / "pages"
61
- watch_dir(
62
- str(pages_dir),
63
- _handle_page_changed,
64
- glob_pattern="*.py",
65
- allow_nonexistent=True,
66
- )
67
- PagesStrategyV1.is_watching_pages_dir = True
68
-
69
- def __init__(self, pages_manager: PagesManager, setup_watcher: bool = True):
70
- self.pages_manager = pages_manager
71
-
72
- if setup_watcher:
73
- PagesStrategyV1.watch_pages_dir(pages_manager)
74
-
75
- @property
76
- def initial_active_script_hash(self) -> PageHash:
77
- return self.pages_manager.current_page_script_hash
78
-
79
- def get_initial_active_script(
80
- self, page_script_hash: PageHash, page_name: PageName
81
- ) -> PageInfo | None:
82
- pages = self.get_pages()
83
-
84
- if page_script_hash:
85
- return pages.get(page_script_hash, None)
86
- elif not page_script_hash and page_name:
87
- # If a user navigates directly to a non-main page of an app, we get
88
- # the first script run request before the list of pages has been
89
- # sent to the frontend. In this case, we choose the first script
90
- # with a name matching the requested page name.
91
- return next(
92
- filter(
93
- # There seems to be this weird bug with mypy where it
94
- # thinks that p can be None (which is impossible given the
95
- # types of pages), so we add `p and` at the beginning of
96
- # the predicate to circumvent this.
97
- lambda p: p and (p["page_name"] == page_name),
98
- pages.values(),
99
- ),
100
- None,
101
- )
102
-
103
- # If no information about what page to run is given, default to
104
- # running the main page.
105
- # Safe because pages will at least contain the app's main page.
106
- main_page_info = list(pages.values())[0]
107
- return main_page_info
108
-
109
- def get_pages(self) -> dict[PageHash, PageInfo]:
110
- return source_util.get_pages(self.pages_manager.main_script_path)
111
-
112
- def register_pages_changed_callback(
113
- self,
114
- callback: Callable[[str], None],
115
- ) -> Callable[[], None]:
116
- return source_util.register_pages_changed_callback(callback)
117
-
118
- def set_pages(self, _pages: dict[PageHash, PageInfo]) -> None:
119
- raise NotImplementedError("Unable to set pages in this V1 strategy")
120
-
121
- def get_page_script(self, _fallback_page_hash: PageHash) -> PageInfo | None:
122
- raise NotImplementedError("Unable to get page script in this V1 strategy")
123
-
124
-
125
- class PagesStrategyV2:
126
- """
127
- Strategy for MPA v2. This strategy handles pages being set directly
128
- by a call to `st.navigation`. The key differences here are:
129
- - The pages are set directly by the user
130
- - The initial active script will always be the main script
131
- - More than one script can run in a single app run (sequentially),
132
- so we must keep track of the active script hash
133
- - We rely on pages manager to retrieve the intended page script per run
134
-
135
- NOTE: We don't provide any locks on the pages since the pages are not
136
- shared across sessions. Only the user script thread can write to
137
- pages and the event loop thread only reads
138
- """
139
-
140
- def __init__(self, pages_manager: PagesManager, **kwargs):
141
- self.pages_manager = pages_manager
142
- self._pages: dict[PageHash, PageInfo] | None = None
143
-
144
- def get_initial_active_script(
145
- self, page_script_hash: PageHash, page_name: PageName
146
- ) -> PageInfo:
147
- return {
148
- # We always run the main script in V2 as it's the common code
149
- "script_path": self.pages_manager.main_script_path,
150
- "page_script_hash": page_script_hash
151
- or self.pages_manager.main_script_hash, # Default Hash
152
- }
153
-
154
- @property
155
- def initial_active_script_hash(self) -> PageHash:
156
- return self.pages_manager.main_script_hash
157
-
158
- def get_page_script(self, fallback_page_hash: PageHash) -> PageInfo | None:
159
- if self._pages is None:
160
- return None
161
-
162
- if self.pages_manager.intended_page_script_hash:
163
- # We assume that if initial page hash is specified, that a page should
164
- # exist, so we check out the page script hash or the default page hash
165
- # as a backup
166
- return self._pages.get(
167
- self.pages_manager.intended_page_script_hash,
168
- self._pages.get(fallback_page_hash, None),
169
- )
170
- elif self.pages_manager.intended_page_name:
171
- # If a user navigates directly to a non-main page of an app, the
172
- # the page name can identify the page script to run
173
- return next(
174
- filter(
175
- # There seems to be this weird bug with mypy where it
176
- # thinks that p can be None (which is impossible given the
177
- # types of pages), so we add `p and` at the beginning of
178
- # the predicate to circumvent this.
179
- lambda p: p
180
- and (p["url_pathname"] == self.pages_manager.intended_page_name),
181
- self._pages.values(),
182
- ),
183
- None,
184
- )
185
-
186
- return self._pages.get(fallback_page_hash, None)
187
-
188
- def get_pages(self) -> dict[PageHash, PageInfo]:
189
- # If pages are not set, provide the common page info where
190
- # - the main script path is the executing script to start
191
- # - the page script hash and name reflects the intended page requested
192
- return self._pages or {
193
- self.pages_manager.main_script_hash: {
194
- "page_script_hash": self.pages_manager.intended_page_script_hash or "",
195
- "page_name": self.pages_manager.intended_page_name or "",
196
- "icon": "",
197
- "script_path": self.pages_manager.main_script_path,
198
- }
199
- }
200
-
201
- def set_pages(self, pages: dict[PageHash, PageInfo]) -> None:
202
- self._pages = pages
203
-
204
- def register_pages_changed_callback(
205
- self,
206
- callback: Callable[[str], None],
207
- ) -> Callable[[], None]:
208
- # V2 strategy does not handle any pages changed event
209
- return lambda: None
210
-
211
-
212
30
  class PagesManager:
213
31
  """
214
- PagesManager is responsible for managing the set of pages based on the
215
- strategy. By default, PagesManager uses V1 which relies on the original
216
- assumption that there exists a `pages` directory with all the scripts.
217
-
218
- If the `pages` are being set directly, the strategy is switched to V2.
219
- This indicates someone has written an `st.navigation` call in their app
220
- which informs us of the pages.
221
-
222
- NOTE: Each strategy handles its own thread safety when accessing the pages
32
+ PagesManager is responsible for managing the set of pages that make up
33
+ the entire application. At the start we assume the main script is the
34
+ only page. As the script runs, the main script can call `st.navigation`
35
+ to set the set of pages that make up the app.
223
36
  """
224
37
 
225
- DefaultStrategy: type[PagesStrategyV1 | PagesStrategyV2] = PagesStrategyV1
38
+ uses_pages_directory: bool | None = None
226
39
 
227
40
  def __init__(
228
41
  self,
@@ -232,11 +45,23 @@ class PagesManager:
232
45
  ):
233
46
  self._main_script_path = main_script_path
234
47
  self._main_script_hash: PageHash = calc_md5(main_script_path)
235
- self.pages_strategy = PagesManager.DefaultStrategy(self, **kwargs)
236
48
  self._script_cache = script_cache
237
49
  self._intended_page_script_hash: PageHash | None = None
238
50
  self._intended_page_name: PageName | None = None
239
51
  self._current_page_script_hash: PageHash = ""
52
+ self._pages: dict[PageHash, PageInfo] | None = None
53
+ # A relic of v1 of Multipage apps, we performed special handling
54
+ # for apps with a pages directory. We will keep this flag around
55
+ # for now to maintain the behavior for apps that were created with
56
+ # the pages directory feature.
57
+ #
58
+ # NOTE: we will update the feature if the flag has not been set
59
+ # this means that if users use v2 behavior, the flag will
60
+ # always be set to False
61
+ if PagesManager.uses_pages_directory is None:
62
+ PagesManager.uses_pages_directory = Path(
63
+ self.main_script_parent / "pages"
64
+ ).exists()
240
65
 
241
66
  @property
242
67
  def main_script_path(self) -> ScriptPath:
@@ -262,14 +87,6 @@ class PagesManager:
262
87
  def intended_page_script_hash(self) -> PageHash | None:
263
88
  return self._intended_page_script_hash
264
89
 
265
- @property
266
- def initial_active_script_hash(self) -> PageHash:
267
- return self.pages_strategy.initial_active_script_hash
268
-
269
- @property
270
- def mpa_version(self) -> int:
271
- return 2 if isinstance(self.pages_strategy, PagesStrategyV2) else 1
272
-
273
90
  def set_current_page_script_hash(self, page_script_hash: PageHash) -> None:
274
91
  self._current_page_script_hash = page_script_hash
275
92
 
@@ -288,45 +105,57 @@ class PagesManager:
288
105
  def get_initial_active_script(
289
106
  self, page_script_hash: PageHash, page_name: PageName
290
107
  ) -> PageInfo | None:
291
- return self.pages_strategy.get_initial_active_script(
292
- page_script_hash, page_name
293
- )
108
+ return {
109
+ # We always run the main script in V2 as it's the common code
110
+ "script_path": self.main_script_path,
111
+ "page_script_hash": page_script_hash
112
+ or self.main_script_hash, # Default Hash
113
+ }
294
114
 
295
115
  def get_pages(self) -> dict[PageHash, PageInfo]:
296
- return self.pages_strategy.get_pages()
116
+ # If pages are not set, provide the common page info where
117
+ # - the main script path is the executing script to start
118
+ # - the page script hash and name reflects the intended page requested
119
+ return self._pages or {
120
+ self.main_script_hash: {
121
+ "page_script_hash": self.intended_page_script_hash or "",
122
+ "page_name": self.intended_page_name or "",
123
+ "icon": "",
124
+ "script_path": self.main_script_path,
125
+ }
126
+ }
297
127
 
298
128
  def set_pages(self, pages: dict[PageHash, PageInfo]) -> None:
299
- # Manually setting the pages indicates we are using MPA v2.
300
- if isinstance(self.pages_strategy, PagesStrategyV1):
301
- if os.path.exists(self.main_script_parent / "pages"):
302
- _LOGGER.warning(
303
- "st.navigation was called in an app with a pages/ directory. "
304
- "This may cause unusual app behavior. You may want to rename the "
305
- "pages/ directory."
306
- )
307
- PagesManager.DefaultStrategy = PagesStrategyV2
308
- self.pages_strategy = PagesStrategyV2(self)
309
-
310
- self.pages_strategy.set_pages(pages)
129
+ self._pages = pages
311
130
 
312
131
  def get_page_script(self, fallback_page_hash: PageHash = "") -> PageInfo | None:
313
- # We assume the pages strategy is V2 cause this is used
314
- # in the st.navigation call, but we just swallow the error
315
- try:
316
- return self.pages_strategy.get_page_script(fallback_page_hash)
317
- except NotImplementedError:
132
+ if self._pages is None:
318
133
  return None
319
134
 
320
- def register_pages_changed_callback(
321
- self,
322
- callback: Callable[[str], None],
323
- ) -> Callable[[], None]:
324
- """Register a callback to be called when the set of pages changes.
325
-
326
- The callback will be called with the path changed.
327
- """
135
+ if self.intended_page_script_hash:
136
+ # We assume that if initial page hash is specified, that a page should
137
+ # exist, so we check out the page script hash or the default page hash
138
+ # as a backup
139
+ return self._pages.get(
140
+ self.intended_page_script_hash,
141
+ self._pages.get(fallback_page_hash, None),
142
+ )
143
+ elif self.intended_page_name:
144
+ # If a user navigates directly to a non-main page of an app, the
145
+ # the page name can identify the page script to run
146
+ return next(
147
+ filter(
148
+ # There seems to be this weird bug with mypy where it
149
+ # thinks that p can be None (which is impossible given the
150
+ # types of pages), so we add `p and` at the beginning of
151
+ # the predicate to circumvent this.
152
+ lambda p: p and (p["url_pathname"] == self.intended_page_name),
153
+ self._pages.values(),
154
+ ),
155
+ None,
156
+ )
328
157
 
329
- return self.pages_strategy.register_pages_changed_callback(callback)
158
+ return self._pages.get(fallback_page_hash, None)
330
159
 
331
160
  def get_page_script_byte_code(self, script_path: str) -> Any:
332
161
  if self._script_cache is None: