1055 lines
37 KiB
Python
1055 lines
37 KiB
Python
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2025)
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
from __future__ import annotations
|
|
|
|
import inspect
|
|
import tempfile
|
|
import textwrap
|
|
import traceback
|
|
from pathlib import Path
|
|
from typing import TYPE_CHECKING, Any, Callable
|
|
from unittest.mock import MagicMock
|
|
from urllib import parse
|
|
|
|
from streamlit.runtime import Runtime
|
|
from streamlit.runtime.caching.storage.dummy_cache_storage import (
|
|
MemoryCacheStorageManager,
|
|
)
|
|
from streamlit.runtime.media_file_manager import MediaFileManager
|
|
from streamlit.runtime.memory_media_file_storage import MemoryMediaFileStorage
|
|
from streamlit.runtime.pages_manager import PagesManager
|
|
from streamlit.runtime.scriptrunner.script_cache import ScriptCache
|
|
from streamlit.runtime.secrets import Secrets
|
|
from streamlit.runtime.state.common import TESTING_KEY
|
|
from streamlit.runtime.state.safe_session_state import SafeSessionState
|
|
from streamlit.runtime.state.session_state import SessionState
|
|
from streamlit.source_util import page_icon_and_name
|
|
from streamlit.testing.v1.element_tree import (
|
|
Block,
|
|
Button,
|
|
ButtonGroup,
|
|
Caption,
|
|
ChatInput,
|
|
ChatMessage,
|
|
Checkbox,
|
|
Code,
|
|
ColorPicker,
|
|
Column,
|
|
Dataframe,
|
|
DateInput,
|
|
Divider,
|
|
ElementList,
|
|
ElementTree,
|
|
Error,
|
|
Exception, # noqa: A004
|
|
Expander,
|
|
Header,
|
|
Info,
|
|
Json,
|
|
Latex,
|
|
Markdown,
|
|
Metric,
|
|
Multiselect,
|
|
Node,
|
|
NumberInput,
|
|
Radio,
|
|
Selectbox,
|
|
SelectSlider,
|
|
Slider,
|
|
Status,
|
|
Subheader,
|
|
Success,
|
|
Tab,
|
|
Table,
|
|
Text,
|
|
TextArea,
|
|
TextInput,
|
|
TimeInput,
|
|
Title,
|
|
Toast,
|
|
Toggle,
|
|
Warning, # noqa: A004
|
|
WidgetList,
|
|
repr_,
|
|
)
|
|
from streamlit.testing.v1.local_script_runner import LocalScriptRunner
|
|
from streamlit.testing.v1.util import patch_config_options
|
|
from streamlit.util import calc_md5
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Iterator, Sequence
|
|
|
|
from streamlit.proto.WidgetStates_pb2 import WidgetStates
|
|
|
|
TMP_DIR = tempfile.TemporaryDirectory()
|
|
|
|
|
|
class AppTest:
|
|
"""
|
|
A simulated Streamlit app to check the correctness of displayed\
|
|
elements and outputs.
|
|
|
|
An instance of ``AppTest`` simulates a running Streamlit app. This class
|
|
provides methods to set up, manipulate, and inspect the app contents via
|
|
API instead of a browser UI. It can be used to write automated tests of an
|
|
app in various scenarios. These can then be run using a tool like pytest.
|
|
|
|
``AppTest`` can be initialized by one of three class methods:
|
|
|
|
* |st.testing.v1.AppTest.from_file|_ (recommended)
|
|
* |st.testing.v1.AppTest.from_string|_
|
|
* |st.testing.v1.AppTest.from_function|_
|
|
|
|
Once initialized, Session State and widget values can be updated and the
|
|
script can be run. Unlike an actual live-running Streamlit app, you need to
|
|
call ``AppTest.run()`` explicitly to re-run the app after changing a widget
|
|
value. Switching pages also requires an explicit, follow-up call to
|
|
``AppTest.run()``.
|
|
|
|
``AppTest`` enables developers to build tests on their app as-is, in the
|
|
familiar python test format, without major refactoring or abstracting out
|
|
logic to be tested separately from the UI. Tests can run quickly with very
|
|
low overhead. A typical pattern is to build a suite of tests for an app
|
|
that ensure consistent functionality as the app evolves, and run the tests
|
|
locally and/or in a CI environment like Github Actions.
|
|
|
|
.. note::
|
|
``AppTest`` only supports testing a single page of an app per
|
|
instance. For multipage apps, each page will need to be tested
|
|
separately. ``AppTest`` is not yet compatible with multipage apps
|
|
using ``st.navigation`` and ``st.Page``.
|
|
|
|
.. |st.testing.v1.AppTest.from_file| replace:: ``st.testing.v1.AppTest.from_file``
|
|
.. _st.testing.v1.AppTest.from_file: #apptestfrom_file
|
|
.. |st.testing.v1.AppTest.from_string| replace:: ``st.testing.v1.AppTest.from_string``
|
|
.. _st.testing.v1.AppTest.from_string: #apptestfrom_string
|
|
.. |st.testing.v1.AppTest.from_function| replace:: ``st.testing.v1.AppTest.from_function``
|
|
.. _st.testing.v1.AppTest.from_function: #apptestfrom_function
|
|
|
|
Attributes
|
|
----------
|
|
secrets: dict[str, Any]
|
|
Dictionary of secrets to be used the simulated app. Use dict-like
|
|
syntax to set secret values for the simulated app.
|
|
|
|
session_state: SafeSessionState
|
|
Session State for the simulated app. SafeSessionState object supports
|
|
read and write operations as usual for Streamlit apps.
|
|
|
|
query_params: dict[str, Any]
|
|
Dictionary of query parameters to be used by the simluated app. Use
|
|
dict-like syntax to set ``query_params`` values for the simulated app.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
script_path: str | Path,
|
|
*,
|
|
default_timeout: float,
|
|
args: tuple[Any, ...] | None = None,
|
|
kwargs: dict[str, Any] | None = None,
|
|
) -> None:
|
|
self._script_path = str(script_path)
|
|
self.default_timeout = default_timeout
|
|
session_state = SessionState()
|
|
session_state[TESTING_KEY] = {}
|
|
self.session_state = SafeSessionState(session_state, lambda: None)
|
|
self.query_params: dict[str, Any] = {}
|
|
self.secrets: dict[str, Any] = {}
|
|
self.args = args
|
|
self.kwargs = kwargs
|
|
self._page_hash = ""
|
|
|
|
tree = ElementTree()
|
|
tree._runner = self
|
|
self._tree = tree
|
|
|
|
@classmethod
|
|
def from_string(cls, script: str, *, default_timeout: float = 3) -> AppTest:
|
|
"""
|
|
Create an instance of ``AppTest`` to simulate an app page defined\
|
|
within a string.
|
|
|
|
This is useful for testing short scripts that fit comfortably as an
|
|
inline string in the test itself, without having to create a separate
|
|
file for it. The script must be executable on its own and so must
|
|
contain all necessary imports.
|
|
|
|
Parameters
|
|
----------
|
|
script: str
|
|
The string contents of the script to be run.
|
|
|
|
default_timeout: float
|
|
Default time in seconds before a script run is timed out. Can be
|
|
overridden for individual ``.run()`` calls.
|
|
|
|
Returns
|
|
-------
|
|
AppTest
|
|
A simulated Streamlit app for testing. The simulated app can be
|
|
executed via ``.run()``.
|
|
|
|
"""
|
|
return cls._from_string(script, default_timeout=default_timeout)
|
|
|
|
@classmethod
|
|
def _from_string(
|
|
cls,
|
|
script: str,
|
|
*,
|
|
default_timeout: float = 3,
|
|
args: tuple[Any, ...] | None = None,
|
|
kwargs: dict[str, Any] | None = None,
|
|
) -> AppTest:
|
|
script_name = calc_md5(bytes(script, "utf-8"))
|
|
|
|
path = Path(TMP_DIR.name, script_name)
|
|
aligned_script = textwrap.dedent(script)
|
|
path.write_text(aligned_script)
|
|
return AppTest(
|
|
str(path), default_timeout=default_timeout, args=args, kwargs=kwargs
|
|
)
|
|
|
|
@classmethod
|
|
def from_function(
|
|
cls,
|
|
script: Callable[..., Any],
|
|
*,
|
|
default_timeout: float = 3,
|
|
args: tuple[Any, ...] | None = None,
|
|
kwargs: dict[str, Any] | None = None,
|
|
) -> AppTest:
|
|
"""
|
|
Create an instance of ``AppTest`` to simulate an app page defined\
|
|
within a function.
|
|
|
|
This is similar to ``AppTest.from_string()``, but more convenient to
|
|
write with IDE assistance. The script must be executable on its own and
|
|
so must contain all necessary imports.
|
|
|
|
Parameters
|
|
----------
|
|
script: Callable
|
|
A function whose body will be used as a script. Must be runnable
|
|
in isolation, so it must include any necessary imports.
|
|
|
|
default_timeout: float
|
|
Default time in seconds before a script run is timed out. Can be
|
|
overridden for individual ``.run()`` calls.
|
|
|
|
args: tuple
|
|
An optional tuple of args to pass to the script function.
|
|
|
|
kwargs: dict
|
|
An optional dict of kwargs to pass to the script function.
|
|
|
|
Returns
|
|
-------
|
|
AppTest
|
|
A simulated Streamlit app for testing. The simulated app can be
|
|
executed via ``.run()``.
|
|
|
|
"""
|
|
source_lines, _ = inspect.getsourcelines(script)
|
|
source = textwrap.dedent("".join(source_lines))
|
|
module = source + f"\n{script.__name__}(*__args, **__kwargs)"
|
|
return cls._from_string(
|
|
module, default_timeout=default_timeout, args=args, kwargs=kwargs
|
|
)
|
|
|
|
@classmethod
|
|
def from_file(
|
|
cls, script_path: str | Path, *, default_timeout: float = 3
|
|
) -> AppTest:
|
|
"""
|
|
Create an instance of ``AppTest`` to simulate an app page defined\
|
|
within a file.
|
|
|
|
This option is most convenient for CI workflows and testing of
|
|
published apps. The script must be executable on its own and so must
|
|
contain all necessary imports.
|
|
|
|
Parameters
|
|
----------
|
|
script_path: str | Path
|
|
Path to a script file. The path should be absolute or relative to
|
|
the file calling ``.from_file``.
|
|
|
|
default_timeout: float
|
|
Default time in seconds before a script run is timed out. Can be
|
|
overridden for individual ``.run()`` calls.
|
|
|
|
Returns
|
|
-------
|
|
AppTest
|
|
A simulated Streamlit app for testing. The simulated app can be
|
|
executed via ``.run()``.
|
|
"""
|
|
script_path = Path(script_path)
|
|
if script_path.is_file():
|
|
path = script_path
|
|
else:
|
|
# TODO: Make this not super fragile
|
|
# Attempt to find the test file calling this method, so the
|
|
# path can be relative to there.
|
|
stack = traceback.StackSummary.extract(traceback.walk_stack(None))
|
|
filepath = Path(stack[1].filename)
|
|
path = filepath.parent / script_path
|
|
return AppTest(path, default_timeout=default_timeout)
|
|
|
|
def _run(
|
|
self,
|
|
widget_state: WidgetStates | None = None,
|
|
timeout: float | None = None,
|
|
) -> AppTest:
|
|
"""Run the script, and parse the output messages for querying
|
|
and interaction.
|
|
|
|
Timeout is in seconds, or None to use the default timeout of the runner.
|
|
"""
|
|
# Have to import the streamlit module itself so replacing st.secrets
|
|
# is visible to other modules.
|
|
import streamlit as st
|
|
|
|
if timeout is None:
|
|
timeout = self.default_timeout
|
|
|
|
# setup
|
|
mock_runtime = MagicMock(spec=Runtime)
|
|
mock_runtime.media_file_mgr = MediaFileManager(
|
|
MemoryMediaFileStorage("/mock/media")
|
|
)
|
|
mock_runtime.cache_storage_manager = MemoryCacheStorageManager()
|
|
Runtime._instance = mock_runtime
|
|
script_cache = ScriptCache()
|
|
pages_manager = PagesManager(
|
|
self._script_path, script_cache, setup_watcher=False
|
|
)
|
|
|
|
saved_secrets: Secrets = st.secrets
|
|
# Only modify global secrets stuff if we have been given secrets
|
|
if self.secrets:
|
|
new_secrets = Secrets()
|
|
new_secrets._secrets = self.secrets
|
|
st.secrets = new_secrets
|
|
|
|
script_runner = LocalScriptRunner(
|
|
self._script_path,
|
|
self.session_state,
|
|
pages_manager,
|
|
args=self.args,
|
|
kwargs=self.kwargs,
|
|
)
|
|
with patch_config_options({"global.appTest": True}):
|
|
self._tree = script_runner.run(
|
|
widget_state, self.query_params, timeout, self._page_hash
|
|
)
|
|
self._tree._runner = self
|
|
# Last event is SHUTDOWN, so the corresponding data includes query string
|
|
query_string = script_runner.event_data[-1]["client_state"].query_string
|
|
self.query_params = parse.parse_qs(query_string)
|
|
|
|
if self.secrets:
|
|
if st.secrets._secrets is not None:
|
|
self.secrets = dict(st.secrets._secrets)
|
|
st.secrets = saved_secrets
|
|
Runtime._instance = None
|
|
|
|
return self
|
|
|
|
def run(self, *, timeout: float | None = None) -> AppTest:
|
|
"""Run the script from the current state.
|
|
|
|
This is equivalent to manually rerunning the app or the rerun that
|
|
occurs upon user interaction. ``AppTest.run()`` must be manually called
|
|
after updating a widget value or switching pages as script reruns do
|
|
not occur automatically as they do for live-running Streamlit apps.
|
|
|
|
Parameters
|
|
----------
|
|
timeout : float or None
|
|
The maximum number of seconds to run the script. If ``timeout`` is
|
|
``None`` (default), Streamlit uses the default timeout set for the
|
|
instance of ``AppTest``.
|
|
|
|
Returns
|
|
-------
|
|
AppTest
|
|
self
|
|
|
|
"""
|
|
return self._tree.run(timeout=timeout)
|
|
|
|
def switch_page(self, page_path: str) -> AppTest:
|
|
"""Switch to another page of the app.
|
|
|
|
This method does not automatically rerun the app. Use a follow-up call
|
|
to ``AppTest.run()`` to obtain the elements on the selected page.
|
|
|
|
Parameters
|
|
----------
|
|
page_path: str
|
|
Path of the page to switch to. The path must be relative to the
|
|
main script's location (e.g. ``"pages/my_page.py"``).
|
|
|
|
Returns
|
|
-------
|
|
AppTest
|
|
self
|
|
|
|
"""
|
|
main_dir = Path(self._script_path).parent
|
|
full_page_path = main_dir / page_path
|
|
if not full_page_path.is_file():
|
|
raise ValueError(
|
|
f"Unable to find script at {page_path}, make sure the page given is relative to the main script."
|
|
)
|
|
page_path_str = str(full_page_path.resolve())
|
|
_, page_name = page_icon_and_name(Path(page_path_str))
|
|
self._page_hash = calc_md5(page_name)
|
|
return self
|
|
|
|
@property
|
|
def main(self) -> Block:
|
|
"""Sequence of elements within the main body of the app.
|
|
|
|
Returns
|
|
-------
|
|
Block
|
|
A container of elements. Block can be queried for elements in the
|
|
same manner as ``AppTest``. For example, ``Block.checkbox`` will
|
|
return all ``st.checkbox`` within the associated container.
|
|
"""
|
|
return self._tree.main
|
|
|
|
@property
|
|
def sidebar(self) -> Block:
|
|
"""Sequence of all elements within ``st.sidebar``.
|
|
|
|
Returns
|
|
-------
|
|
Block
|
|
A container of elements. Block can be queried for elements in the
|
|
same manner as ``AppTest``. For example, ``Block.checkbox`` will
|
|
return all ``st.checkbox`` within the associated container.
|
|
"""
|
|
return self._tree.sidebar
|
|
|
|
@property
|
|
def button(self) -> WidgetList[Button]:
|
|
"""Sequence of all ``st.button`` and ``st.form_submit_button`` widgets.
|
|
|
|
Returns
|
|
-------
|
|
WidgetList of Button
|
|
Sequence of all ``st.button`` and ``st.form_submit_button``
|
|
widgets. Individual widgets can be accessed from a WidgetList by
|
|
index (order on the page) or key. For example, ``at.button[0]`` for
|
|
the first widget or ``at.button(key="my_key")`` for a widget with a
|
|
given key.
|
|
"""
|
|
return self._tree.button
|
|
|
|
@property
|
|
def button_group(self) -> WidgetList[ButtonGroup[Any]]:
|
|
"""Sequence of all ``st.feedback`` widgets.
|
|
|
|
Returns
|
|
-------
|
|
WidgetList of ButtonGroup
|
|
Sequence of all ``st.feedback`` widgets. Individual widgets can be
|
|
accessed from a WidgetList by index (order on the page) or key. For
|
|
example, ``at.button_group[0]`` for the first widget or
|
|
``at.button_group(key="my_key")`` for a widget with a given key.
|
|
"""
|
|
return self._tree.button_group
|
|
|
|
@property
|
|
def caption(self) -> ElementList[Caption]:
|
|
"""Sequence of all ``st.caption`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Caption
|
|
Sequence of all ``st.caption`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.caption[0]`` for the first element. Caption is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.caption
|
|
|
|
@property
|
|
def chat_input(self) -> WidgetList[ChatInput]:
|
|
"""Sequence of all ``st.chat_input`` widgets.
|
|
|
|
Returns
|
|
-------
|
|
WidgetList of ChatInput
|
|
Sequence of all ``st.chat_input`` widgets. Individual widgets can
|
|
be accessed from a WidgetList by index (order on the page) or key.
|
|
For example, ``at.chat_input[0]`` for the first widget or
|
|
``at.chat_input(key="my_key")`` for a widget with a given key.
|
|
"""
|
|
return self._tree.chat_input
|
|
|
|
@property
|
|
def chat_message(self) -> Sequence[ChatMessage]:
|
|
"""Sequence of all ``st.chat_message`` elements.
|
|
|
|
Returns
|
|
-------
|
|
Sequence of ChatMessage
|
|
Sequence of all ``st.chat_message`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.chat_message[0]`` for the first element. ChatMessage
|
|
is an extension of the Block class.
|
|
"""
|
|
return self._tree.chat_message
|
|
|
|
@property
|
|
def checkbox(self) -> WidgetList[Checkbox]:
|
|
"""Sequence of all ``st.checkbox`` widgets.
|
|
|
|
Returns
|
|
-------
|
|
WidgetList of Checkbox
|
|
Sequence of all ``st.checkbox`` widgets. Individual widgets can
|
|
be accessed from a WidgetList by index (order on the page) or key.
|
|
For example, ``at.checkbox[0]`` for the first widget or
|
|
``at.checkbox(key="my_key")`` for a widget with a given key.
|
|
"""
|
|
return self._tree.checkbox
|
|
|
|
@property
|
|
def code(self) -> ElementList[Code]:
|
|
"""Sequence of all ``st.code`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Code
|
|
Sequence of all ``st.code`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.code[0]`` for the first element. Code is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.code
|
|
|
|
@property
|
|
def color_picker(self) -> WidgetList[ColorPicker]:
|
|
"""Sequence of all ``st.color_picker`` widgets.
|
|
|
|
Returns
|
|
-------
|
|
WidgetList of ColorPicker
|
|
Sequence of all ``st.color_picker`` widgets. Individual widgets can
|
|
be accessed from a WidgetList by index (order on the page) or key.
|
|
For example, ``at.color_picker[0]`` for the first widget or
|
|
``at.color_picker(key="my_key")`` for a widget with a given key.
|
|
"""
|
|
return self._tree.color_picker
|
|
|
|
@property
|
|
def columns(self) -> Sequence[Column]:
|
|
"""Sequence of all columns within ``st.columns`` elements.
|
|
|
|
Each column within a single ``st.columns`` will be returned as a
|
|
separate Column in the Sequence.
|
|
|
|
Returns
|
|
-------
|
|
Sequence of Column
|
|
Sequence of all columns within ``st.columns`` elements. Individual
|
|
columns can be accessed from an ElementList by index (order on the
|
|
page). For example, ``at.columns[0]`` for the first column. Column
|
|
is an extension of the Block class.
|
|
"""
|
|
return self._tree.columns
|
|
|
|
@property
|
|
def dataframe(self) -> ElementList[Dataframe]:
|
|
"""Sequence of all ``st.dataframe`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Dataframe
|
|
Sequence of all ``st.dataframe`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.dataframe[0]`` for the first element. Dataframe is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.dataframe
|
|
|
|
@property
|
|
def date_input(self) -> WidgetList[DateInput]:
|
|
"""Sequence of all ``st.date_input`` widgets.
|
|
|
|
Returns
|
|
-------
|
|
WidgetList of DateInput
|
|
Sequence of all ``st.date_input`` widgets. Individual widgets can
|
|
be accessed from a WidgetList by index (order on the page) or key.
|
|
For example, ``at.date_input[0]`` for the first widget or
|
|
``at.date_input(key="my_key")`` for a widget with a given key.
|
|
"""
|
|
return self._tree.date_input
|
|
|
|
@property
|
|
def divider(self) -> ElementList[Divider]:
|
|
"""Sequence of all ``st.divider`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Divider
|
|
Sequence of all ``st.divider`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.divider[0]`` for the first element. Divider is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.divider
|
|
|
|
@property
|
|
def error(self) -> ElementList[Error]:
|
|
"""Sequence of all ``st.error`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Error
|
|
Sequence of all ``st.error`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.error[0]`` for the first element. Error is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.error
|
|
|
|
@property
|
|
def exception(self) -> ElementList[Exception]:
|
|
"""Sequence of all ``st.exception`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Exception
|
|
Sequence of all ``st.exception`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.exception[0]`` for the first element. Exception is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.exception
|
|
|
|
@property
|
|
def expander(self) -> Sequence[Expander]:
|
|
"""Sequence of all ``st.expander`` elements.
|
|
|
|
Returns
|
|
-------
|
|
Sequence of Expandable
|
|
Sequence of all ``st.expander`` elements. Individual elements can be
|
|
accessed from a Sequence by index (order on the page). For
|
|
example, ``at.expander[0]`` for the first element. Expandable is an
|
|
extension of the Block class.
|
|
"""
|
|
return self._tree.expander
|
|
|
|
@property
|
|
def header(self) -> ElementList[Header]:
|
|
"""Sequence of all ``st.header`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Header
|
|
Sequence of all ``st.header`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.header[0]`` for the first element. Header is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.header
|
|
|
|
@property
|
|
def info(self) -> ElementList[Info]:
|
|
"""Sequence of all ``st.info`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Info
|
|
Sequence of all ``st.info`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.info[0]`` for the first element. Info is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.info
|
|
|
|
@property
|
|
def json(self) -> ElementList[Json]:
|
|
"""Sequence of all ``st.json`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Json
|
|
Sequence of all ``st.json`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.json[0]`` for the first element. Json is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.json
|
|
|
|
@property
|
|
def latex(self) -> ElementList[Latex]:
|
|
"""Sequence of all ``st.latex`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Latex
|
|
Sequence of all ``st.latex`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.latex[0]`` for the first element. Latex is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.latex
|
|
|
|
@property
|
|
def markdown(self) -> ElementList[Markdown]:
|
|
"""Sequence of all ``st.markdown`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Markdown
|
|
Sequence of all ``st.markdown`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.markdown[0]`` for the first element. Markdown is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.markdown
|
|
|
|
@property
|
|
def metric(self) -> ElementList[Metric]:
|
|
"""Sequence of all ``st.metric`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Metric
|
|
Sequence of all ``st.metric`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.metric[0]`` for the first element. Metric is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.metric
|
|
|
|
@property
|
|
def multiselect(self) -> WidgetList[Multiselect[Any]]:
|
|
"""Sequence of all ``st.multiselect`` widgets.
|
|
|
|
Returns
|
|
-------
|
|
WidgetList of Multiselect
|
|
Sequence of all ``st.multiselect`` widgets. Individual widgets can
|
|
be accessed from a WidgetList by index (order on the page) or key.
|
|
For example, ``at.multiselect[0]`` for the first widget or
|
|
``at.multiselect(key="my_key")`` for a widget with a given key.
|
|
"""
|
|
return self._tree.multiselect
|
|
|
|
@property
|
|
def number_input(self) -> WidgetList[NumberInput]:
|
|
"""Sequence of all ``st.number_input`` widgets.
|
|
|
|
Returns
|
|
-------
|
|
WidgetList of NumberInput
|
|
Sequence of all ``st.number_input`` widgets. Individual widgets can
|
|
be accessed from a WidgetList by index (order on the page) or key.
|
|
For example, ``at.number_input[0]`` for the first widget or
|
|
``at.number_input(key="my_key")`` for a widget with a given key.
|
|
"""
|
|
return self._tree.number_input
|
|
|
|
@property
|
|
def radio(self) -> WidgetList[Radio[Any]]:
|
|
"""Sequence of all ``st.radio`` widgets.
|
|
|
|
Returns
|
|
-------
|
|
WidgetList of Radio
|
|
Sequence of all ``st.radio`` widgets. Individual widgets can
|
|
be accessed from a WidgetList by index (order on the page) or key.
|
|
For example, ``at.radio[0]`` for the first widget or
|
|
``at.radio(key="my_key")`` for a widget with a given key.
|
|
"""
|
|
return self._tree.radio
|
|
|
|
@property
|
|
def select_slider(self) -> WidgetList[SelectSlider[Any]]:
|
|
"""Sequence of all ``st.select_slider`` widgets.
|
|
|
|
Returns
|
|
-------
|
|
WidgetList of SelectSlider
|
|
Sequence of all ``st.select_slider`` widgets. Individual widgets can
|
|
be accessed from a WidgetList by index (order on the page) or key.
|
|
For example, ``at.select_slider[0]`` for the first widget or
|
|
``at.select_slider(key="my_key")`` for a widget with a given key.
|
|
"""
|
|
return self._tree.select_slider
|
|
|
|
@property
|
|
def selectbox(self) -> WidgetList[Selectbox[Any]]:
|
|
"""Sequence of all ``st.selectbox`` widgets.
|
|
|
|
Returns
|
|
-------
|
|
WidgetList of Selectbox
|
|
Sequence of all ``st.selectbox`` widgets. Individual widgets can
|
|
be accessed from a WidgetList by index (order on the page) or key.
|
|
For example, ``at.selectbox[0]`` for the first widget or
|
|
``at.selectbox(key="my_key")`` for a widget with a given key.
|
|
"""
|
|
return self._tree.selectbox
|
|
|
|
@property
|
|
def slider(self) -> WidgetList[Slider[Any]]:
|
|
"""Sequence of all ``st.slider`` widgets.
|
|
|
|
Returns
|
|
-------
|
|
WidgetList of Slider
|
|
Sequence of all ``st.slider`` widgets. Individual widgets can
|
|
be accessed from a WidgetList by index (order on the page) or key.
|
|
For example, ``at.slider[0]`` for the first widget or
|
|
``at.slider(key="my_key")`` for a widget with a given key.
|
|
"""
|
|
return self._tree.slider
|
|
|
|
@property
|
|
def subheader(self) -> ElementList[Subheader]:
|
|
"""Sequence of all ``st.subheader`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Subheader
|
|
Sequence of all ``st.subheader`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.subheader[0]`` for the first element. Subheader is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.subheader
|
|
|
|
@property
|
|
def success(self) -> ElementList[Success]:
|
|
"""Sequence of all ``st.success`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Success
|
|
Sequence of all ``st.success`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.success[0]`` for the first element. Success is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.success
|
|
|
|
@property
|
|
def status(self) -> Sequence[Status]:
|
|
"""Sequence of all ``st.status`` elements.
|
|
|
|
Returns
|
|
-------
|
|
Sequence of Status
|
|
Sequence of all ``st.status`` elements. Individual elements can be
|
|
accessed from a Sequence by index (order on the page). For
|
|
example, ``at.status[0]`` for the first element. Status is an
|
|
extension of the Block class.
|
|
"""
|
|
return self._tree.status
|
|
|
|
@property
|
|
def table(self) -> ElementList[Table]:
|
|
"""Sequence of all ``st.table`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Table
|
|
Sequence of all ``st.table`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.table[0]`` for the first element. Table is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.table
|
|
|
|
@property
|
|
def tabs(self) -> Sequence[Tab]:
|
|
"""Sequence of all tabs within ``st.tabs`` elements.
|
|
|
|
Each tab within a single ``st.tabs`` will be returned as a separate Tab
|
|
in the Sequence. Additionally, the tab labels are forwarded to each
|
|
Tab element as a property. For example, ``st.tabs("A","B")`` will
|
|
yield two Tab objects, with ``Tab.label`` returning "A" and "B",
|
|
respectively.
|
|
|
|
Returns
|
|
-------
|
|
Sequence of Tab
|
|
Sequence of all tabs within ``st.tabs`` elements. Individual
|
|
tabs can be accessed from an ElementList by index (order on the
|
|
page). For example, ``at.tabs[0]`` for the first tab. Tab is an
|
|
extension of the Block class.
|
|
"""
|
|
return self._tree.tabs
|
|
|
|
@property
|
|
def text(self) -> ElementList[Text]:
|
|
"""Sequence of all ``st.text`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Text
|
|
Sequence of all ``st.text`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.text[0]`` for the first element. Text is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.text
|
|
|
|
@property
|
|
def text_area(self) -> WidgetList[TextArea]:
|
|
"""Sequence of all ``st.text_area`` widgets.
|
|
|
|
Returns
|
|
-------
|
|
WidgetList of TextArea
|
|
Sequence of all ``st.text_area`` widgets. Individual widgets can
|
|
be accessed from a WidgetList by index (order on the page) or key.
|
|
For example, ``at.text_area[0]`` for the first widget or
|
|
``at.text_area(key="my_key")`` for a widget with a given key.
|
|
"""
|
|
return self._tree.text_area
|
|
|
|
@property
|
|
def text_input(self) -> WidgetList[TextInput]:
|
|
"""Sequence of all ``st.text_input`` widgets.
|
|
|
|
Returns
|
|
-------
|
|
WidgetList of TextInput
|
|
Sequence of all ``st.text_input`` widgets. Individual widgets can
|
|
be accessed from a WidgetList by index (order on the page) or key.
|
|
For example, ``at.text_input[0]`` for the first widget or
|
|
``at.text_input(key="my_key")`` for a widget with a given key.
|
|
"""
|
|
return self._tree.text_input
|
|
|
|
@property
|
|
def time_input(self) -> WidgetList[TimeInput]:
|
|
"""Sequence of all ``st.time_input`` widgets.
|
|
|
|
Returns
|
|
-------
|
|
WidgetList of TimeInput
|
|
Sequence of all ``st.time_input`` widgets. Individual widgets can
|
|
be accessed from a WidgetList by index (order on the page) or key.
|
|
For example, ``at.time_input[0]`` for the first widget or
|
|
``at.time_input(key="my_key")`` for a widget with a given key.
|
|
"""
|
|
return self._tree.time_input
|
|
|
|
@property
|
|
def title(self) -> ElementList[Title]:
|
|
"""Sequence of all ``st.title`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Title
|
|
Sequence of all ``st.title`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.title[0]`` for the first element. Title is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.title
|
|
|
|
@property
|
|
def toast(self) -> ElementList[Toast]:
|
|
"""Sequence of all ``st.toast`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Toast
|
|
Sequence of all ``st.toast`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.toast[0]`` for the first element. Toast is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.toast
|
|
|
|
@property
|
|
def toggle(self) -> WidgetList[Toggle]:
|
|
"""Sequence of all ``st.toggle`` widgets.
|
|
|
|
Returns
|
|
-------
|
|
WidgetList of Toggle
|
|
Sequence of all ``st.toggle`` widgets. Individual widgets can
|
|
be accessed from a WidgetList by index (order on the page) or key.
|
|
For example, ``at.toggle[0]`` for the first widget or
|
|
``at.toggle(key="my_key")`` for a widget with a given key.
|
|
"""
|
|
return self._tree.toggle
|
|
|
|
@property
|
|
def warning(self) -> ElementList[Warning]:
|
|
"""Sequence of all ``st.warning`` elements.
|
|
|
|
Returns
|
|
-------
|
|
ElementList of Warning
|
|
Sequence of all ``st.warning`` elements. Individual elements can be
|
|
accessed from an ElementList by index (order on the page). For
|
|
example, ``at.warning[0]`` for the first element. Warning is an
|
|
extension of the Element class.
|
|
"""
|
|
return self._tree.warning
|
|
|
|
def __len__(self) -> int:
|
|
return len(self._tree)
|
|
|
|
def __iter__(self) -> Iterator[Node]:
|
|
yield from self._tree
|
|
|
|
def __getitem__(self, idx: int) -> Node:
|
|
return self._tree[idx]
|
|
|
|
def get(self, element_type: str) -> Sequence[Node]:
|
|
"""Get elements or widgets of the specified type.
|
|
|
|
This method returns the collection of all elements or widgets of
|
|
the specified type on the current page. Retrieve a specific element by
|
|
using its index (order on page) or key lookup.
|
|
|
|
Parameters
|
|
----------
|
|
element_type: str
|
|
An element attribute of ``AppTest``. For example, "button",
|
|
"caption", or "chat_input".
|
|
|
|
Returns
|
|
-------
|
|
Sequence of Elements
|
|
Sequence of elements of the given type. Individual elements can
|
|
be accessed from a Sequence by index (order on the page). When
|
|
getting and ``element_type`` that is a widget, individual widgets
|
|
can be accessed by key. For example, ``at.get("text")[0]`` for the
|
|
first ``st.text`` element or ``at.get("slider")(key="my_key")`` for
|
|
the ``st.slider`` widget with a given key.
|
|
"""
|
|
return self._tree.get(element_type)
|
|
|
|
def __repr__(self) -> str:
|
|
return repr_(self)
|