streamlit-nightly 1.42.2.dev20250219__py2.py3-none-any.whl → 1.42.3.dev20250221__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 (84) hide show
  1. streamlit/column_config.py +2 -0
  2. streamlit/commands/navigation.py +134 -129
  3. streamlit/elements/lib/column_types.py +88 -0
  4. streamlit/elements/widgets/button.py +14 -4
  5. streamlit/navigation/page.py +1 -1
  6. streamlit/proto/DownloadButton_pb2.py +2 -2
  7. streamlit/proto/DownloadButton_pb2.pyi +4 -1
  8. streamlit/runtime/credentials.py +15 -16
  9. streamlit/static/index.html +1 -1
  10. streamlit/static/static/js/{FileDownload.esm.gA2YL2Ws.js → FileDownload.esm.DuVgDmcS.js} +1 -1
  11. streamlit/static/static/js/{FileDropzone.CFdsfZRc.js → FileDropzone.BS-xq2Wx.js} +1 -1
  12. streamlit/static/static/js/{FormClearHelper.CUy5uXTm.js → FormClearHelper.J8fZuqYI.js} +1 -1
  13. streamlit/static/static/js/{Hooks.DK2XYjwG.js → Hooks.CNPngtZ4.js} +1 -1
  14. streamlit/static/static/js/{InputInstructions.BliBOyQ3.js → InputInstructions.DxmXu3Kw.js} +1 -1
  15. streamlit/static/static/js/{ProgressBar.x1Isa69D.js → ProgressBar.CP8g842E.js} +2 -2
  16. streamlit/static/static/js/{RenderInPortalIfExists.BAeceYUy.js → RenderInPortalIfExists.BmyUtUFH.js} +1 -1
  17. streamlit/static/static/js/{Toolbar.CT8DybSu.js → Toolbar.Blrz1JFA.js} +1 -1
  18. streamlit/static/static/js/{base-input.DCz9tkLd.js → base-input.DAIA4gfk.js} +4 -4
  19. streamlit/static/static/js/{createSuper.C7LhI0EH.js → createSuper.BswKD9F8.js} +1 -1
  20. streamlit/static/static/js/{data-grid-overlay-editor.BCdg4YOG.js → data-grid-overlay-editor.ZgD3BQ2B.js} +1 -1
  21. streamlit/static/static/js/{downloader.vdos0sUi.js → downloader.inME8iMy.js} +1 -1
  22. streamlit/static/static/js/{es6.DwFVXqV3.js → es6.dJLzqtYk.js} +2 -2
  23. streamlit/static/static/js/{iframeResizer.contentWindow.RYpo13Tx.js → iframeResizer.contentWindow.cu30BTN5.js} +1 -1
  24. streamlit/static/static/js/{index.C5SUBN7c.js → index.15SsDzez.js} +2 -2
  25. streamlit/static/static/js/{index.DuxM9Tnh.js → index.8XyAnl0R.js} +1 -1
  26. streamlit/static/static/js/{index.CpJnG_8d.js → index.B3VXnAul.js} +1 -1
  27. streamlit/static/static/js/{index.zBfRJuNm.js → index.B6uPGZtQ.js} +1 -1
  28. streamlit/static/static/js/{index.BZeSmopR.js → index.BEt2OXG5.js} +2 -2
  29. streamlit/static/static/js/index.BlB7rnTn.js +1 -0
  30. streamlit/static/static/js/{index.DCnVdrNR.js → index.BpzSSPzO.js} +1 -1
  31. streamlit/static/static/js/{index.BkCG7aTj.js → index.BsvDo8AN.js} +1 -1
  32. streamlit/static/static/js/{index.DA71zvn-.js → index.C7zdEYEp.js} +1 -1
  33. streamlit/static/static/js/{index.DSORXUAZ.js → index.CEppeFo7.js} +3 -3
  34. streamlit/static/static/js/{index.BGAu9NKr.js → index.COuF5EvL.js} +132 -132
  35. streamlit/static/static/js/{index.C-qg2uWr.js → index.CSHKQq-E.js} +1 -1
  36. streamlit/static/static/js/{index.Ya6ZDkVG.js → index.CXN1_deM.js} +2 -2
  37. streamlit/static/static/js/{index.XBfbnu7R.js → index.CaOtLhyp.js} +1 -1
  38. streamlit/static/static/js/index.CiQ5wFJ4.js +197 -0
  39. streamlit/static/static/js/{index.CO-uFT7b.js → index.CkkCzLC4.js} +1 -1
  40. streamlit/static/static/js/{index.CYAXfbfU.js → index.D0JGWsXt.js} +1 -1
  41. streamlit/static/static/js/{index.B7_aOrfa.js → index.D3ck1U_t.js} +1 -1
  42. streamlit/static/static/js/{index.BpjiEyUX.js → index.DCSd7Qvs.js} +1 -1
  43. streamlit/static/static/js/{index.B6ax18R8.js → index.DKSgHmwp.js} +2 -2
  44. streamlit/static/static/js/{index.D8iwKK7d.js → index.DOR9yDu0.js} +1 -1
  45. streamlit/static/static/js/index.DP8260wA.js +1 -0
  46. streamlit/static/static/js/{index.D0h2TgPB.js → index.DTLj_1B2.js} +1 -1
  47. streamlit/static/static/js/{index.CYBSRaVx.js → index.DVbJ3S8t.js} +1 -1
  48. streamlit/static/static/js/{index.DTik05yh.js → index.DYt-QfCo.js} +1 -1
  49. streamlit/static/static/js/{index.DFovZsvy.js → index.DodktFqu.js} +1 -1
  50. streamlit/static/static/js/{index.CTtluRFB.js → index.DrBQDoQQ.js} +118 -118
  51. streamlit/static/static/js/{index.DGog6RGy.js → index.DuUWd9QG.js} +1 -1
  52. streamlit/static/static/js/{index.rOQjzSJF.js → index.DwtqIbpw.js} +1 -1
  53. streamlit/static/static/js/{index.C53pKB0j.js → index.DzNuTqK_.js} +1 -1
  54. streamlit/static/static/js/{index.CaA1VIZR.js → index.FAZrrIPA.js} +1 -1
  55. streamlit/static/static/js/{index.CP5mPDkY.js → index.FWCmBif3.js} +3 -3
  56. streamlit/static/static/js/{index.BdXu9OaH.js → index.IxWSvNzu.js} +1 -1
  57. streamlit/static/static/js/index.R2TOukZ5.js +1 -0
  58. streamlit/static/static/js/{index.CbM0IQPr.js → index.Uaqj8cqD.js} +1 -1
  59. streamlit/static/static/js/{index.Dh8M84uS.js → index.eyZOSwoi.js} +1 -1
  60. streamlit/static/static/js/{index.DTMcwebh.js → index.z1uqruy0.js} +1 -1
  61. streamlit/static/static/js/{input.DI1DKx6K.js → input.CQjL36Th.js} +2 -2
  62. streamlit/static/static/js/{memory.Bys8G1q2.js → memory.579OACx4.js} +1 -1
  63. streamlit/static/static/js/{mergeWith.CQCg1Krv.js → mergeWith.B8KJCMOJ.js} +1 -1
  64. streamlit/static/static/js/{number-overlay-editor.C7xqWB6m.js → number-overlay-editor.Dv1b6l7M.js} +1 -1
  65. streamlit/static/static/js/{possibleConstructorReturn.CoBITkSn.js → possibleConstructorReturn.CYnI8sYw.js} +1 -1
  66. streamlit/static/static/js/{sandbox.DhWaUNlZ.js → sandbox.V2eglMiZ.js} +1 -1
  67. streamlit/static/static/js/{textarea.BBYT1EyU.js → textarea.DpOEcgWS.js} +2 -2
  68. streamlit/static/static/js/{timepicker.BNm3w13Y.js → timepicker.CVUWU8gJ.js} +1 -1
  69. streamlit/static/static/js/{toConsumableArray.CdvkF-LC.js → toConsumableArray.BuIIwYQO.js} +1 -1
  70. streamlit/static/static/js/{uniqueId.C4bthDRw.js → uniqueId.DzFqVlA_.js} +1 -1
  71. streamlit/static/static/js/{useBasicWidgetState.B8drr2-Z.js → useBasicWidgetState.Clt8VY2K.js} +1 -1
  72. streamlit/static/static/js/{useOnInputChange.DxZMmV5y.js → useOnInputChange.B7h174Ym.js} +1 -1
  73. streamlit/static/static/js/{withFullScreenWrapper.KpXeL4S_.js → withFullScreenWrapper.md187TEa.js} +1 -1
  74. streamlit/web/bootstrap.py +10 -6
  75. {streamlit_nightly-1.42.2.dev20250219.dist-info → streamlit_nightly-1.42.3.dev20250221.dist-info}/METADATA +1 -1
  76. {streamlit_nightly-1.42.2.dev20250219.dist-info → streamlit_nightly-1.42.3.dev20250221.dist-info}/RECORD +80 -80
  77. streamlit/static/static/js/index.C1c-PWwv.js +0 -1
  78. streamlit/static/static/js/index.C5Vmgs5Q.js +0 -1
  79. streamlit/static/static/js/index.Dc1YdleN.js +0 -197
  80. streamlit/static/static/js/index.DgLxA-9p.js +0 -1
  81. {streamlit_nightly-1.42.2.dev20250219.data → streamlit_nightly-1.42.3.dev20250221.data}/scripts/streamlit.cmd +0 -0
  82. {streamlit_nightly-1.42.2.dev20250219.dist-info → streamlit_nightly-1.42.3.dev20250221.dist-info}/WHEEL +0 -0
  83. {streamlit_nightly-1.42.2.dev20250219.dist-info → streamlit_nightly-1.42.3.dev20250221.dist-info}/entry_points.txt +0 -0
  84. {streamlit_nightly-1.42.2.dev20250219.dist-info → streamlit_nightly-1.42.3.dev20250221.dist-info}/top_level.txt +0 -0
@@ -32,6 +32,7 @@ __all__ = [
32
32
  "ListColumn",
33
33
  "DateColumn",
34
34
  "TimeColumn",
35
+ "JsonColumn",
35
36
  ]
36
37
 
37
38
 
@@ -43,6 +44,7 @@ from streamlit.elements.lib.column_types import (
43
44
  DateColumn,
44
45
  DatetimeColumn,
45
46
  ImageColumn,
47
+ JsonColumn,
46
48
  LineChartColumn,
47
49
  LinkColumn,
48
50
  ListColumn,
@@ -15,12 +15,13 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  from pathlib import Path
18
- from typing import TYPE_CHECKING, Literal
18
+ from typing import TYPE_CHECKING, Callable, Literal
19
19
 
20
20
  from typing_extensions import TypeAlias
21
21
 
22
22
  from streamlit import config
23
23
  from streamlit.errors import StreamlitAPIException
24
+ from streamlit.navigation.page import StreamlitPage
24
25
  from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
25
26
  from streamlit.proto.Navigation_pb2 import Navigation as NavigationProto
26
27
  from streamlit.runtime.metrics_util import gather_metrics
@@ -30,12 +31,34 @@ from streamlit.runtime.scriptrunner_utils.script_run_context import (
30
31
  )
31
32
 
32
33
  if TYPE_CHECKING:
33
- from streamlit.navigation.page import StreamlitPage
34
34
  from streamlit.source_util import PageHash, PageInfo
35
35
 
36
36
  SectionHeader: TypeAlias = str
37
37
 
38
38
 
39
+ def convert_to_streamlit_page(
40
+ page_input: str | Path | Callable[[], None] | StreamlitPage,
41
+ ) -> StreamlitPage:
42
+ """Convert various input types to StreamlitPage objects."""
43
+ if isinstance(page_input, StreamlitPage):
44
+ return page_input
45
+
46
+ if isinstance(page_input, str):
47
+ return StreamlitPage(page_input)
48
+
49
+ if isinstance(page_input, Path):
50
+ return StreamlitPage(page_input)
51
+
52
+ if callable(page_input):
53
+ # Convert function to StreamlitPage
54
+ return StreamlitPage(page_input)
55
+
56
+ raise StreamlitAPIException(
57
+ f"Invalid page type: {type(page_input)}. Must be either a string path, "
58
+ "a pathlib.Path, a callable function, or a st.Page object."
59
+ )
60
+
61
+
39
62
  def pages_from_nav_sections(
40
63
  nav_sections: dict[SectionHeader, list[StreamlitPage]],
41
64
  ) -> list[StreamlitPage]:
@@ -55,7 +78,8 @@ def send_page_not_found(ctx: ScriptRunContext):
55
78
 
56
79
  @gather_metrics("navigation")
57
80
  def navigation(
58
- pages: list[StreamlitPage] | dict[SectionHeader, list[StreamlitPage]],
81
+ pages: list[str | Path | Callable[[], None] | StreamlitPage]
82
+ | dict[SectionHeader, list[str | Path | Callable[[], None] | StreamlitPage]],
59
83
  *,
60
84
  position: Literal["sidebar", "hidden"] = "sidebar",
61
85
  expanded: bool = False,
@@ -63,161 +87,142 @@ def navigation(
63
87
  """
64
88
  Configure the available pages in a multipage app.
65
89
 
66
- Call ``st.navigation`` in your entrypoint file with one or more pages
67
- defined by ``st.Page``. ``st.navigation`` returns the current page, which
68
- can be executed using ``.run()`` method.
90
+ Call ``st.navigation`` in your entrypoint file to define the structure and navigation
91
+ of your multipage application. The function accepts pages defined as file paths,
92
+ callable functions, or StreamlitPage objects. It returns the current page, which
93
+ can be executed using the ``.run()`` method.
69
94
 
70
- When using ``st.navigation``, your entrypoint file (the file passed to
71
- ``streamlit run``) acts like a router or frame of common elements around
72
- each of your pages. Streamlit executes the entrypoint file with every app
73
- rerun. To execute the current page, you must call the ``.run()`` method on
95
+ When using ``st.navigation``, your entrypoint file acts as a router or frame
96
+ containing common elements for all pages. Streamlit executes the entrypoint file
97
+ with every app rerun. To execute the current page, call the ``.run()`` method on
74
98
  the ``StreamlitPage`` object returned by ``st.navigation``.
75
99
 
76
- The set of available pages can be updated with each rerun for dynamic
77
- navigation. By default, ``st.navigation`` draws the available pages in the
78
- side navigation if there is more than one page. This behavior can be
79
- changed using the ``position`` keyword argument.
100
+ The set of available pages can be dynamically updated with each rerun.
101
+ By default, the navigation menu appears in the sidebar if there is more than
102
+ one page. This behavior can be modified using the ``position`` parameter.
80
103
 
81
- As soon as any session of your app executes the ``st.navigation`` command,
82
- your app will ignore the ``pages/`` directory (across all sessions).
104
+ Note: When any session of your app executes ``st.navigation``, the app will
105
+ ignore the ``pages/`` directory across all sessions.
83
106
 
84
107
  Parameters
85
108
  ----------
86
- pages : list[StreamlitPage] or dict[str, list[StreamlitPage]]
87
- The available pages for the app.
88
-
89
- To create labeled sections or page groupings within the navigation
90
- menu, ``pages`` must be a dictionary. Each key is the label of a
91
- section and each value is the list of ``StreamlitPage`` objects for
92
- that section.
93
-
94
- To create a navigation menu with no sections or page groupings,
95
- ``pages`` must be a list of ``StreamlitPage`` objects.
96
-
97
- Use ``st.Page`` to create ``StreamlitPage`` objects.
98
-
99
- position : "sidebar" or "hidden"
100
- The position of the navigation menu. If ``position`` is ``"sidebar"``
101
- (default), the navigation widget appears at the top of the sidebar. If
102
- ``position`` is ``"hidden"``, the navigation widget is not displayed.
103
-
104
- If there is only one page in ``pages``, the navigation will be hidden
105
- for any value of ``position``.
109
+ pages : Union[List[Union[str, Path, Callable, StreamlitPage]], Dict[str, List[Union[str, Path, Callable, StreamlitPage]]]]
110
+ The available pages for the app. Can be specified in several ways:
111
+
112
+ As a list:
113
+ - List of file paths as strings or Path objects (e.g., ["page1.py", Path("page2.py")])
114
+ - List of callable functions (e.g., [page1_func, page2_func])
115
+ - List of StreamlitPage objects (e.g., [st.Page("page1.py"), st.Page(page2_func)])
116
+ - Mixed list of the above types
117
+
118
+ As a dictionary for grouped sections:
119
+ - Keys are section labels
120
+ - Values are lists containing any combination of the above types
121
+
122
+ Example dictionary:
123
+ {
124
+ "Section 1": ["page1.py", Path("page2.py"), page3_func],
125
+ "Section 2": [st.Page("page3.py")]
126
+ }
127
+
128
+ position : Literal["sidebar", "hidden"]
129
+ Controls the navigation menu position:
130
+ - "sidebar" (default): Places the navigation at the top of the sidebar
131
+ - "hidden": Hides the navigation widget
132
+ Note: Navigation is always hidden when there's only one page.
106
133
 
107
134
  expanded : bool
108
- Whether the navigation menu should be expanded. If this is ``False``
109
- (default), the navigation menu will be collapsed and will include a
110
- button to view more options when there are too many pages to display.
111
- If this is ``True``, the navigation menu will always be expanded; no
112
- button to collapse the menu will be displayed.
113
-
114
- If ``st.navigation`` changes from ``expanded=True`` to
115
- ``expanded=False`` on a rerun, the menu will stay expanded and a
116
- collapse button will be displayed.
135
+ Controls the navigation menu's expansion state:
136
+ - False (default): Menu starts collapsed with a "more" button
137
+ - True: Menu stays permanently expanded
138
+ Note: When changing from True to False, the menu remains expanded
139
+ but displays a collapse button.
117
140
 
118
141
  Returns
119
142
  -------
120
143
  StreamlitPage
121
- The current page selected by the user.
144
+ The currently selected page object that can be executed with .run()
122
145
 
123
146
  Examples
124
147
  --------
125
- The following examples show possible entrypoint files, which is the file
126
- you pass to ``streamlit run``. Your entrypoint file manages your app's
127
- navigation and serves as a router between pages.
128
-
129
- **Example 1: Use a callable or Python file as a page**
130
-
131
- You can declare pages from callables or file paths.
132
-
133
- ``page_1.py`` (in the same directory as your entrypoint file):
134
-
148
+ Basic usage with file paths:
135
149
  >>> import streamlit as st
150
+ >>> pages = ["home.py", "about.py", "contact.py"]
151
+ >>> page = st.navigation(pages)
152
+ >>> page.run()
153
+
154
+ Using functions as pages:
155
+ >>> def home():
156
+ ... st.title("Home")
157
+ >>> def about():
158
+ ... st.title("About")
136
159
  >>>
137
- >>> st.title("Page 1")
138
-
139
- Your entrypoint file:
160
+ >>> pages = [home, about]
161
+ >>> page = st.navigation(pages)
162
+ >>> page.run()
140
163
 
141
- >>> import streamlit as st
142
- >>>
143
- >>> def page_2():
144
- ... st.title("Page 2")
145
- >>>
146
- >>> pg = st.navigation([st.Page("page_1.py"), st.Page(page_2)])
147
- >>> pg.run()
148
-
149
- .. output::
150
- https://doc-navigation-example-1.streamlit.app/
151
- height: 200px
152
-
153
- **Example 2: Group pages into sections**
154
-
155
- You can use a dictionary to create sections within your navigation menu. In
156
- the following example, each page is similar to Page 1 in Example 1, and all
157
- pages are in the same directory. However, you can use Python files from
158
- anywhere in your repository. For more information, see |st.Page|_.
159
-
160
- Directory structure:
161
-
162
- >>> your_repository/
163
- >>> ├── create_account.py
164
- >>> ├── learn.py
165
- >>> ├── manage_account.py
166
- >>> ├── streamlit_app.py
167
- >>> └── trial.py
168
-
169
- ``streamlit_app.py``:
170
-
171
- >>> import streamlit as st
172
- >>>
164
+ Mixed usage with sections:
173
165
  >>> pages = {
174
- ... "Your account": [
175
- ... st.Page("create_account.py", title="Create your account"),
176
- ... st.Page("manage_account.py", title="Manage your account"),
177
- ... ],
178
- ... "Resources": [
179
- ... st.Page("learn.py", title="Learn about us"),
180
- ... st.Page("trial.py", title="Try it out"),
181
- ... ],
166
+ ... "Main": ["home.py", about_func],Page
167
+ ... "Info": [st.Page("help.py", title="Help Center")],
182
168
  ... }
183
- >>>
184
- >>> pg = st.navigation(pages)
185
- >>> pg.run()
186
-
187
- .. output::
188
- https://doc-navigation-example-2.streamlit.app/
189
- height: 300px
169
+ >>> page = st.navigation(pages)
170
+ >>> page.run()
190
171
 
191
- **Example 3: Stateful widgets across multiple pages**
192
-
193
- Call widget functions in your entrypoint file when you want a widget to be
194
- stateful across pages. Assign keys to your common widgets and access their
195
- values through Session State within your pages.
196
-
197
- >>> import streamlit as st
198
- >>>
172
+ Stateful widgets across pages:
199
173
  >>> def page1():
200
- >>> st.write(st.session_state.foo)
201
- >>>
174
+ ... st.write(st.session_state.user_name)
202
175
  >>> def page2():
203
- >>> st.write(st.session_state.bar)
176
+ ... st.write(st.session_state.user_email)
204
177
  >>>
205
- >>> # Widgets shared by all the pages
206
- >>> st.sidebar.selectbox("Foo", ["A", "B", "C"], key="foo")
207
- >>> st.sidebar.checkbox("Bar", key="bar")
178
+ >>> # Common widgets in entrypoint
179
+ >>> st.text_input("Name", key="user_name")
180
+ >>> st.text_input("Email", key="user_email")
208
181
  >>>
209
- >>> pg = st.navigation([st.Page(page1), st.Page(page2)])
210
- >>> pg.run()
182
+ >>> page = st.navigation([page1, page2])
183
+ >>> page.run()
211
184
 
212
- .. output::
213
- https://doc-navigation-multipage-widgets.streamlit.app/
214
- height: 350px
215
-
216
- .. |st.Page| replace:: ``st.Page``
217
- .. _st.Page: https://docs.streamlit.io/develop/api-reference/navigation/st.page
185
+ Using Path objects:
186
+ >>> from pathlib import Path
187
+ >>> pages = [Path("home.py"), Path("about.py")]
188
+ >>> page = st.navigation(pages)
189
+ >>> page.run()
218
190
 
191
+ Mixed usage with Path and sections:
192
+ >>> pages = {
193
+ ... "Main": [Path("home.py"), about_func],
194
+ ... "Info": [st.Page(Path("help.py"), title="Help Center")],
195
+ ... }
196
+ >>> page = st.navigation(pages)
197
+ >>> page.run()
198
+
199
+ Raises
200
+ ------
201
+ StreamlitAPIException
202
+ In the following cases:
203
+ - No pages provided
204
+ - Multiple pages set as default
205
+ - Duplicate URL pathnames
206
+ - Invalid page type provided
207
+
208
+ Notes
209
+ -----
210
+ - File paths can be relative or absolute
211
+ - Function names are used as default page titles
212
+ - URL pathnames must be unique across all pages
213
+ - Only one page can be set as default
214
+ - The first page is automatically set as default if none specified
215
+ - Common widgets should be defined in the entrypoint file for state sharing
219
216
  """
220
- nav_sections = {"": pages} if isinstance(pages, list) else pages
217
+ if isinstance(pages, list):
218
+ converted_pages = [convert_to_streamlit_page(p) for p in pages]
219
+ nav_sections = {"": converted_pages}
220
+ else:
221
+ nav_sections = {
222
+ section: [convert_to_streamlit_page(p) for p in section_pages]
223
+ for section, section_pages in pages.items()
224
+ }
225
+
221
226
  page_list = pages_from_nav_sections(nav_sections)
222
227
 
223
228
  if not page_list:
@@ -56,6 +56,7 @@ ColumnType: TypeAlias = Literal[
56
56
  "area_chart",
57
57
  "image",
58
58
  "progress",
59
+ "json",
59
60
  ]
60
61
 
61
62
 
@@ -149,6 +150,10 @@ class ProgressColumnConfig(TypedDict):
149
150
  max_value: NotRequired[int | float | None]
150
151
 
151
152
 
153
+ class JsonColumnConfig(TypedDict):
154
+ type: Literal["json"]
155
+
156
+
152
157
  class ColumnConfig(TypedDict, total=False):
153
158
  """Configuration options for columns in ``st.dataframe`` and ``st.data_editor``.
154
159
 
@@ -232,6 +237,7 @@ class ColumnConfig(TypedDict, total=False):
232
237
  | BarChartColumnConfig
233
238
  | AreaChartColumnConfig
234
239
  | ImageColumnConfig
240
+ | JsonColumnConfig
235
241
  | None
236
242
  )
237
243
 
@@ -2067,3 +2073,85 @@ def ProgressColumn(
2067
2073
  max_value=max_value,
2068
2074
  ),
2069
2075
  )
2076
+
2077
+
2078
+ @gather_metrics("column_config.JsonColumn")
2079
+ def JsonColumn(
2080
+ label: str | None = None,
2081
+ *,
2082
+ width: ColumnWidth | None = None,
2083
+ help: str | None = None,
2084
+ pinned: bool | None = None,
2085
+ ) -> ColumnConfig:
2086
+ """Configure a JSON column in ``st.dataframe`` or ``st.data_editor``.
2087
+
2088
+ Cells need to contain a JSON string or JSON-compatible objects.
2089
+ JSON columns are not editable at the moment. This command needs to be used in the
2090
+ ``column_config`` parameter of ``st.dataframe`` or ``st.data_editor``.
2091
+
2092
+ Parameters
2093
+ ----------
2094
+
2095
+ label: str or None
2096
+ The label shown at the top of the column. If this is ``None``
2097
+ (default), the column name is used.
2098
+
2099
+ width: "small", "medium", "large", or None
2100
+ The display width of the column. If this is ``None`` (default), the
2101
+ column will be sized to fit the cell contents. Otherwise, this can be
2102
+ one of the following:
2103
+
2104
+ - ``"small"``: 75px wide
2105
+ - ``"medium"``: 200px wide
2106
+ - ``"large"``: 400px wide
2107
+
2108
+ help: str or None
2109
+ An optional tooltip that gets displayed when hovering over the column
2110
+ label. If this is ``None`` (default), no tooltip is displayed.
2111
+
2112
+ pinned: bool or None
2113
+ Whether the column is pinned. A pinned column will stay visible on the
2114
+ left side no matter where the user scrolls. If this is ``None``
2115
+ (default), Streamlit will decide: index columns are pinned, and data
2116
+ columns are not pinned.
2117
+
2118
+ Examples
2119
+ --------
2120
+
2121
+ >>> import pandas as pd
2122
+ >>> import streamlit as st
2123
+ >>>
2124
+ >>> data_df = pd.DataFrame(
2125
+ >>> {
2126
+ >>> "json": [
2127
+ >>> {"foo": "bar", "bar": "baz"},
2128
+ >>> {"foo": "baz", "bar": "qux"},
2129
+ >>> {"foo": "qux", "bar": "foo"},
2130
+ >>> None,
2131
+ >>> ],
2132
+ >>> }
2133
+ >>> )
2134
+ >>>
2135
+ >>> st.dataframe(
2136
+ >>> data_df,
2137
+ >>> column_config={
2138
+ >>> "json": st.column_config.JsonColumn(
2139
+ >>> "JSON Data",
2140
+ >>> help="JSON strings or objects",
2141
+ >>> width="large",
2142
+ >>> ),
2143
+ >>> },
2144
+ >>> hide_index=True,
2145
+ >>> )
2146
+
2147
+ .. output::
2148
+ https://doc-json-column.streamlit.app/
2149
+ height: 300px
2150
+ """
2151
+ return ColumnConfig(
2152
+ label=label,
2153
+ width=width,
2154
+ help=help,
2155
+ pinned=pinned,
2156
+ type_config=JsonColumnConfig(type="json"),
2157
+ )
@@ -264,7 +264,7 @@ class ButtonMixin:
264
264
  mime: str | None = None,
265
265
  key: Key | None = None,
266
266
  help: str | None = None,
267
- on_click: WidgetCallback | None = None,
267
+ on_click: WidgetCallback | Literal["rerun", "ignore"] | None = "rerun",
268
268
  args: WidgetArgs | None = None,
269
269
  kwargs: WidgetKwargs | None = None,
270
270
  *, # keyword-only arguments:
@@ -712,7 +712,7 @@ class ButtonMixin:
712
712
  mime: str | None = None,
713
713
  key: Key | None = None,
714
714
  help: str | None = None,
715
- on_click: WidgetCallback | None = None,
715
+ on_click: WidgetCallback | Literal["rerun", "ignore"] | None = "rerun",
716
716
  args: WidgetArgs | None = None,
717
717
  kwargs: WidgetKwargs | None = None,
718
718
  *, # keyword-only arguments:
@@ -724,10 +724,15 @@ class ButtonMixin:
724
724
  ) -> bool:
725
725
  key = to_key(key)
726
726
 
727
+ if on_click == "ignore" or on_click == "rerun":
728
+ on_click_callback = None
729
+ else:
730
+ on_click_callback = on_click
731
+
727
732
  check_widget_policies(
728
733
  self.dg,
729
734
  key,
730
- on_click,
735
+ on_click_callback,
731
736
  default_value=None,
732
737
  writes_allowed=False,
733
738
  )
@@ -768,11 +773,16 @@ class ButtonMixin:
768
773
  if icon is not None:
769
774
  download_button_proto.icon = validate_icon_or_emoji(icon)
770
775
 
776
+ if on_click == "ignore":
777
+ download_button_proto.ignore_rerun = True
778
+ else:
779
+ download_button_proto.ignore_rerun = False
780
+
771
781
  serde = ButtonSerde()
772
782
 
773
783
  button_state = register_widget(
774
784
  download_button_proto.id,
775
- on_change_handler=on_click,
785
+ on_change_handler=on_click_callback,
776
786
  args=args,
777
787
  kwargs=kwargs,
778
788
  deserializer=serde.deserialize,
@@ -34,7 +34,7 @@ def Page(
34
34
  icon: str | None = None,
35
35
  url_path: str | None = None,
36
36
  default: bool = False,
37
- ):
37
+ ) -> StreamlitPage:
38
38
  """Configure a page for ``st.navigation`` in a multipage app.
39
39
 
40
40
  Call ``st.Page`` to initialize a ``StreamlitPage`` object, and pass it to
@@ -14,7 +14,7 @@ _sym_db = _symbol_database.Default()
14
14
 
15
15
 
16
16
 
17
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n$streamlit/proto/DownloadButton.proto\"\xb3\x01\n\x0e\x44ownloadButton\x12\n\n\x02id\x18\x01 \x01(\t\x12\r\n\x05label\x18\x02 \x01(\t\x12\x0f\n\x07\x64\x65\x66\x61ult\x18\x03 \x01(\x08\x12\x0c\n\x04help\x18\x04 \x01(\t\x12\x0f\n\x07\x66orm_id\x18\x05 \x01(\t\x12\x0b\n\x03url\x18\x06 \x01(\t\x12\x10\n\x08\x64isabled\x18\x07 \x01(\x08\x12\x1b\n\x13use_container_width\x18\x08 \x01(\x08\x12\x0c\n\x04type\x18\t \x01(\t\x12\x0c\n\x04icon\x18\n \x01(\tB3\n\x1c\x63om.snowflake.apps.streamlitB\x13\x44ownloadButtonProtob\x06proto3')
17
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n$streamlit/proto/DownloadButton.proto\"\xc9\x01\n\x0e\x44ownloadButton\x12\n\n\x02id\x18\x01 \x01(\t\x12\r\n\x05label\x18\x02 \x01(\t\x12\x0f\n\x07\x64\x65\x66\x61ult\x18\x03 \x01(\x08\x12\x0c\n\x04help\x18\x04 \x01(\t\x12\x0f\n\x07\x66orm_id\x18\x05 \x01(\t\x12\x0b\n\x03url\x18\x06 \x01(\t\x12\x10\n\x08\x64isabled\x18\x07 \x01(\x08\x12\x1b\n\x13use_container_width\x18\x08 \x01(\x08\x12\x0c\n\x04type\x18\t \x01(\t\x12\x0c\n\x04icon\x18\n \x01(\t\x12\x14\n\x0cignore_rerun\x18\x0b \x01(\x08\x42\x33\n\x1c\x63om.snowflake.apps.streamlitB\x13\x44ownloadButtonProtob\x06proto3')
18
18
 
19
19
  _globals = globals()
20
20
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -23,5 +23,5 @@ if not _descriptor._USE_C_DESCRIPTORS:
23
23
  _globals['DESCRIPTOR']._loaded_options = None
24
24
  _globals['DESCRIPTOR']._serialized_options = b'\n\034com.snowflake.apps.streamlitB\023DownloadButtonProto'
25
25
  _globals['_DOWNLOADBUTTON']._serialized_start=41
26
- _globals['_DOWNLOADBUTTON']._serialized_end=220
26
+ _globals['_DOWNLOADBUTTON']._serialized_end=242
27
27
  # @@protoc_insertion_point(module_scope)
@@ -38,6 +38,7 @@ class DownloadButton(google.protobuf.message.Message):
38
38
  USE_CONTAINER_WIDTH_FIELD_NUMBER: builtins.int
39
39
  TYPE_FIELD_NUMBER: builtins.int
40
40
  ICON_FIELD_NUMBER: builtins.int
41
+ IGNORE_RERUN_FIELD_NUMBER: builtins.int
41
42
  id: builtins.str
42
43
  label: builtins.str
43
44
  default: builtins.bool
@@ -48,6 +49,7 @@ class DownloadButton(google.protobuf.message.Message):
48
49
  use_container_width: builtins.bool
49
50
  type: builtins.str
50
51
  icon: builtins.str
52
+ ignore_rerun: builtins.bool
51
53
  def __init__(
52
54
  self,
53
55
  *,
@@ -61,7 +63,8 @@ class DownloadButton(google.protobuf.message.Message):
61
63
  use_container_width: builtins.bool = ...,
62
64
  type: builtins.str = ...,
63
65
  icon: builtins.str = ...,
66
+ ignore_rerun: builtins.bool = ...,
64
67
  ) -> None: ...
65
- def ClearField(self, field_name: typing.Literal["default", b"default", "disabled", b"disabled", "form_id", b"form_id", "help", b"help", "icon", b"icon", "id", b"id", "label", b"label", "type", b"type", "url", b"url", "use_container_width", b"use_container_width"]) -> None: ...
68
+ def ClearField(self, field_name: typing.Literal["default", b"default", "disabled", b"disabled", "form_id", b"form_id", "help", b"help", "icon", b"icon", "id", b"id", "ignore_rerun", b"ignore_rerun", "label", b"label", "type", b"type", "url", b"url", "use_container_width", b"use_container_width"]) -> None: ...
66
69
 
67
70
  global___DownloadButton = DownloadButton
@@ -20,7 +20,6 @@ import json
20
20
  import os
21
21
  import sys
22
22
  import textwrap
23
- from datetime import datetime, timezone
24
23
  from typing import Final, NamedTuple, NoReturn
25
24
  from uuid import uuid4
26
25
 
@@ -67,42 +66,42 @@ Collecting usage statistics. To deactivate, set browser.gatherUsageStats to fals
67
66
 
68
67
 
69
68
  def _send_email(email: str) -> None:
70
- """Send the user's email to segment.io, if submitted"""
69
+ """Send the user's email for metrics, if submitted"""
71
70
  import requests
72
71
 
73
72
  if email is None or "@" not in email:
74
73
  return
75
74
 
75
+ metrics_url = ""
76
+ try:
77
+ response_json = requests.get(
78
+ "https://data.streamlit.io/metrics.json", timeout=2
79
+ ).json()
80
+ metrics_url = response_json.get("url", "")
81
+ except Exception:
82
+ _LOGGER.error("Failed to fetch metrics URL")
83
+ return
84
+
76
85
  headers = {
77
- "authority": "api.segment.io",
78
86
  "accept": "*/*",
79
87
  "accept-language": "en-US,en;q=0.9",
80
- "content-type": "text/plain",
88
+ "content-type": "application/json",
81
89
  "origin": "localhost:8501",
82
90
  "referer": "localhost:8501/",
83
91
  }
84
92
 
85
- dt = f"{datetime.now(timezone.utc).isoformat()}+00:00"
86
-
87
93
  data = {
88
94
  "anonymous_id": None,
89
- "context": {
90
- "library": {"name": "analytics-python", "version": "2.2.2"},
91
- },
92
95
  "messageId": str(uuid4()),
93
- "timestamp": dt,
94
96
  "event": "submittedEmail",
95
- "traits": {
96
- "authoremail": email,
97
- "source": "provided_email",
98
- },
97
+ "author_email": email,
98
+ "source": "provided_email",
99
99
  "type": "track",
100
100
  "userId": email,
101
- "writeKey": "iCkMy7ymtJ9qYzQRXkQpnAJEq7D4NyMU",
102
101
  }
103
102
 
104
103
  response = requests.post(
105
- "https://api.segment.io/v1/t",
104
+ metrics_url,
106
105
  headers=headers,
107
106
  data=json.dumps(data).encode(),
108
107
  )
@@ -51,7 +51,7 @@
51
51
  <script>
52
52
  window.prerenderReady = false
53
53
  </script>
54
- <script type="module" crossorigin src="./static/js/index.CTtluRFB.js"></script>
54
+ <script type="module" crossorigin src="./static/js/index.DrBQDoQQ.js"></script>
55
55
  <link rel="stylesheet" crossorigin href="./static/css/index.DpJG_94W.css">
56
56
  </head>
57
57
  <body>
@@ -1 +1 @@
1
- import{r as e,E as n,_ as a}from"./index.CTtluRFB.js";var o=e.forwardRef(function(t,r){var l={fill:"currentColor",xmlns:"http://www.w3.org/2000/svg"};return e.createElement(n,a({iconAttrs:l,iconVerticalAlign:"middle",iconViewBox:"0 0 24 24"},t,{ref:r}),e.createElement("path",{fill:"none",d:"M0 0h24v24H0V0z"}),e.createElement("path",{d:"M16 9v10H8V9h8m-1.5-6h-5l-1 1H5v2h14V4h-3.5l-1-1zM18 7H6v12c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7z"}))});o.displayName="Delete";var i=e.forwardRef(function(t,r){var l={fill:"currentColor",xmlns:"http://www.w3.org/2000/svg"};return e.createElement(n,a({iconAttrs:l,iconVerticalAlign:"middle",iconViewBox:"0 0 24 24"},t,{ref:r}),e.createElement("rect",{width:24,height:24,fill:"none"}),e.createElement("path",{d:"M18 15v3H6v-3H4v3c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-3h-2zm-1-4l-1.41-1.41L13 12.17V4h-2v8.17L8.41 9.59 7 11l5 5 5-5z"}))});i.displayName="FileDownload";export{o as D,i as F};
1
+ import{r as e,E as n,_ as a}from"./index.DrBQDoQQ.js";var o=e.forwardRef(function(t,r){var l={fill:"currentColor",xmlns:"http://www.w3.org/2000/svg"};return e.createElement(n,a({iconAttrs:l,iconVerticalAlign:"middle",iconViewBox:"0 0 24 24"},t,{ref:r}),e.createElement("path",{fill:"none",d:"M0 0h24v24H0V0z"}),e.createElement("path",{d:"M16 9v10H8V9h8m-1.5-6h-5l-1 1H5v2h14V4h-3.5l-1-1zM18 7H6v12c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7z"}))});o.displayName="Delete";var i=e.forwardRef(function(t,r){var l={fill:"currentColor",xmlns:"http://www.w3.org/2000/svg"};return e.createElement(n,a({iconAttrs:l,iconVerticalAlign:"middle",iconViewBox:"0 0 24 24"},t,{ref:r}),e.createElement("rect",{width:24,height:24,fill:"none"}),e.createElement("path",{d:"M18 15v3H6v-3H4v3c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-3h-2zm-1-4l-1.41-1.41L13 12.17V4h-2v8.17L8.41 9.59 7 11l5 5 5-5z"}))});i.displayName="FileDownload";export{o as D,i as F};