Viewing File: /home/ubuntu/combine_ai/combine/lib/python3.10/site-packages/streamlit/commands/page_config.py

# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2024)
#
# 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 random
from textwrap import dedent
from typing import TYPE_CHECKING, Final, Literal, Mapping, Union, cast

from typing_extensions import TypeAlias

from streamlit.elements import image
from streamlit.errors import StreamlitAPIException
from streamlit.proto.ForwardMsg_pb2 import ForwardMsg as ForwardProto
from streamlit.proto.PageConfig_pb2 import PageConfig as PageConfigProto
from streamlit.runtime.metrics_util import gather_metrics
from streamlit.runtime.scriptrunner import get_script_run_ctx
from streamlit.string_util import is_emoji, validate_material_icon
from streamlit.url_util import is_url
from streamlit.util import lower_clean_dict_keys

if TYPE_CHECKING:
    from typing_extensions import TypeGuard

GET_HELP_KEY: Final = "get help"
REPORT_A_BUG_KEY: Final = "report a bug"
ABOUT_KEY: Final = "about"

PageIcon: TypeAlias = Union[image.AtomicImage, str]
Layout: TypeAlias = Literal["centered", "wide"]
InitialSideBarState: TypeAlias = Literal["auto", "expanded", "collapsed"]
_GetHelp: TypeAlias = Literal["Get help", "Get Help", "get help"]
_ReportABug: TypeAlias = Literal["Report a bug", "report a bug"]
_About: TypeAlias = Literal["About", "about"]
MenuKey: TypeAlias = Literal[_GetHelp, _ReportABug, _About]
MenuItems: TypeAlias = Mapping[MenuKey, Union[str, None]]

# Emojis recommended by https://share.streamlit.io/rensdimmendaal/emoji-recommender/main/app/streamlit.py
# for the term "streamlit". Watch out for zero-width joiners,
# as they won't parse correctly in the list() call!
RANDOM_EMOJIS: Final = list(
    "๐Ÿ”ฅโ„ข๐ŸŽ‰๐Ÿš€๐ŸŒŒ๐Ÿ’ฃโœจ๐ŸŒ™๐ŸŽ†๐ŸŽ‡๐Ÿ’ฅ๐Ÿคฉ๐Ÿค™๐ŸŒ›๐Ÿค˜โฌ†๐Ÿ’ก๐Ÿคช๐Ÿฅ‚โšก๐Ÿ’จ๐ŸŒ ๐ŸŽŠ๐Ÿฟ๐Ÿ˜›๐Ÿ”ฎ๐ŸคŸ๐ŸŒƒ๐Ÿƒ๐Ÿพ๐Ÿ’ซโ–ช๐ŸŒด๐ŸŽˆ๐ŸŽฌ๐ŸŒ€๐ŸŽ„๐Ÿ˜โ˜”โ›ฝ๐Ÿ‚๐Ÿ’ƒ๐Ÿ˜Ž๐Ÿธ๐ŸŽจ๐Ÿฅณโ˜€๐Ÿ˜๐Ÿ…ฑ๐ŸŒž๐Ÿ˜ป๐ŸŒŸ๐Ÿ˜œ๐Ÿ’ฆ๐Ÿ’…๐Ÿฆ„๐Ÿ˜‹๐Ÿ˜‰๐Ÿ‘ป๐Ÿ๐Ÿคค๐Ÿ‘ฏ๐ŸŒปโ€ผ๐ŸŒˆ๐Ÿ‘Œ๐ŸŽƒ๐Ÿ’›๐Ÿ˜š๐Ÿ”ซ๐Ÿ™Œ๐Ÿ‘ฝ๐Ÿฌ๐ŸŒ…โ˜๐Ÿท๐Ÿ‘ญโ˜•๐ŸŒš๐Ÿ’๐Ÿ‘…๐Ÿฅฐ๐Ÿœ๐Ÿ˜Œ๐ŸŽฅ๐Ÿ•บโ•๐Ÿงกโ˜„๐Ÿ’•๐Ÿปโœ…๐ŸŒธ๐Ÿšฌ๐Ÿค“๐Ÿนยฎโ˜บ๐Ÿ’ช๐Ÿ˜™โ˜˜๐Ÿค โœŠ๐Ÿค—๐Ÿต๐Ÿคž๐Ÿ˜‚๐Ÿ’ฏ๐Ÿ˜๐Ÿ“ป๐ŸŽ‚๐Ÿ’—๐Ÿ’œ๐ŸŒŠโฃ๐ŸŒ๐Ÿ˜˜๐Ÿ’†๐Ÿค‘๐ŸŒฟ๐Ÿฆ‹๐Ÿ˜ˆโ›„๐Ÿšฟ๐Ÿ˜Š๐ŸŒน๐Ÿฅด๐Ÿ˜ฝ๐Ÿ’‹๐Ÿ˜ญ๐Ÿ–ค๐Ÿ™†๐Ÿ‘โšช๐Ÿ’Ÿโ˜ƒ๐Ÿ™ˆ๐Ÿญ๐Ÿ’ป๐Ÿฅ€๐Ÿš—๐Ÿคง๐Ÿ๐Ÿ’Ž๐Ÿ’“๐Ÿค๐Ÿ’„๐Ÿ’–๐Ÿ”žโ‰โฐ๐Ÿ•Š๐ŸŽงโ˜ โ™ฅ๐ŸŒณ๐Ÿพ๐Ÿ™‰โญ๐Ÿ’Š๐Ÿณ๐ŸŒŽ๐Ÿ™Š๐Ÿ’ธโค๐Ÿ”ช๐Ÿ˜†๐ŸŒพโœˆ๐Ÿ“š๐Ÿ’€๐Ÿ โœŒ๐Ÿƒ๐ŸŒต๐Ÿšจ๐Ÿ’‚๐Ÿคซ๐Ÿคญ๐Ÿ˜—๐Ÿ˜„๐Ÿ’๐Ÿ‘๐Ÿ™ƒ๐Ÿ––๐Ÿ’ž๐Ÿ˜…๐ŸŽ…๐Ÿ„๐Ÿ†“๐Ÿ‘‰๐Ÿ’ฉ๐Ÿ”Š๐ŸคทโŒš๐Ÿ‘ธ๐Ÿ˜‡๐Ÿšฎ๐Ÿ’๐Ÿ‘ณ๐Ÿฝ๐Ÿ’˜๐Ÿ’ฟ๐Ÿ’‰๐Ÿ‘ ๐ŸŽผ๐ŸŽถ๐ŸŽค๐Ÿ‘—โ„๐Ÿ”๐ŸŽต๐Ÿค’๐Ÿฐ๐Ÿ‘“๐Ÿ„๐ŸŒฒ๐ŸŽฎ๐Ÿ™‚๐Ÿ“ˆ๐Ÿš™๐Ÿ“๐Ÿ˜ต๐Ÿ—ฃโ—๐ŸŒบ๐Ÿ™„๐Ÿ‘„๐Ÿš˜๐Ÿฅบ๐ŸŒ๐Ÿกโ™ฆ๐Ÿ’๐ŸŒฑ๐Ÿ‘‘๐Ÿ‘™โ˜‘๐Ÿ‘พ๐Ÿฉ๐Ÿฅถ๐Ÿ“ฃ๐Ÿผ๐Ÿคฃโ˜ฏ๐Ÿ‘ต๐Ÿซโžก๐ŸŽ€๐Ÿ˜ƒโœ‹๐Ÿž๐Ÿ™‡๐Ÿ˜น๐Ÿ™๐Ÿ‘ผ๐Ÿโšซ๐ŸŽ๐Ÿช๐Ÿ”จ๐ŸŒผ๐Ÿ‘†๐Ÿ‘€๐Ÿ˜ณ๐ŸŒ๐Ÿ“–๐Ÿ‘ƒ๐ŸŽธ๐Ÿ‘ง๐Ÿ’‡๐Ÿ”’๐Ÿ’™๐Ÿ˜žโ›…๐Ÿป๐Ÿด๐Ÿ˜ผ๐Ÿ—ฟ๐Ÿ—โ™ ๐Ÿฆโœ”๐Ÿค–โ˜ฎ๐Ÿข๐ŸŽ๐Ÿ’ค๐Ÿ˜€๐Ÿบ๐Ÿ˜๐Ÿ˜ด๐Ÿ“บโ˜น๐Ÿ˜ฒ๐Ÿ‘๐ŸŽญ๐Ÿ’š๐Ÿ†๐Ÿ‹๐Ÿ”ต๐Ÿ๐Ÿ”ด๐Ÿ””๐Ÿง๐Ÿ‘ฐโ˜Ž๐Ÿ†๐Ÿคก๐Ÿ ๐Ÿ“ฒ๐Ÿ™‹๐Ÿ“Œ๐Ÿฌโœ๐Ÿ”‘๐Ÿ“ฑ๐Ÿ’ฐ๐Ÿฑ๐Ÿ’ง๐ŸŽ“๐Ÿ•๐Ÿ‘Ÿ๐Ÿฃ๐Ÿ‘ซ๐Ÿ‘๐Ÿ˜ธ๐Ÿฆ๐Ÿ‘๐Ÿ†—๐ŸŽฏ๐Ÿ“ข๐Ÿšถ๐Ÿฆ…๐Ÿง๐Ÿ’ข๐Ÿ€๐Ÿšซ๐Ÿ’‘๐ŸŸ๐ŸŒฝ๐ŸŠ๐ŸŸ๐Ÿ’๐Ÿ’ฒ๐Ÿ๐Ÿฅ๐Ÿธโ˜โ™ฃ๐Ÿ‘Šโš“โŒ๐Ÿฏ๐Ÿˆ๐Ÿ“ฐ๐ŸŒง๐Ÿ‘ฟ๐Ÿณ๐Ÿ’ท๐Ÿบ๐Ÿ“ž๐Ÿ†’๐Ÿ€๐Ÿค๐Ÿšฒ๐Ÿ”๐Ÿ‘น๐Ÿ™๐ŸŒท๐Ÿ™Ž๐Ÿฅ๐Ÿ’ต๐Ÿ”๐Ÿ“ธโš โ“๐ŸŽฉโœ‚๐Ÿผ๐Ÿ˜‘โฌ‡โšพ๐ŸŽ๐Ÿ’”๐Ÿ”โšฝ๐Ÿ’ญ๐ŸŒ๐Ÿท๐Ÿโœ–๐Ÿ‡๐Ÿ“๐ŸŠ๐Ÿ™๐Ÿ‘‹๐Ÿค”๐ŸฅŠ๐Ÿ—ฝ๐Ÿ‘๐Ÿ˜๐Ÿฐ๐Ÿ’๐Ÿดโ™€๐Ÿฆ๐Ÿ“โœ๐Ÿ‘‚๐Ÿด๐Ÿ‘‡๐Ÿ†˜๐Ÿ˜ก๐Ÿ‰๐Ÿ‘ฉ๐Ÿ’Œ๐Ÿ˜บโœ๐Ÿผ๐Ÿ’๐Ÿถ๐Ÿ‘บ๐Ÿ–•๐Ÿ‘ฌ๐Ÿ‰๐Ÿป๐Ÿพโฌ…โฌโ–ถ๐Ÿ‘ฎ๐ŸŒโ™‚๐Ÿ”ธ๐Ÿ‘ถ๐Ÿฎ๐Ÿ‘ชโ›ณ๐Ÿ๐ŸŽพ๐Ÿ•๐Ÿ‘ด๐Ÿจ๐ŸŠ๐Ÿ”นยฉ๐ŸŽฃ๐Ÿ‘ฆ๐Ÿ‘ฃ๐Ÿ‘จ๐Ÿ‘ˆ๐Ÿ’ฌโญ•๐Ÿ“น๐Ÿ“ท"
)

# Also pick out some vanity emojis.
ENG_EMOJIS: Final = [
    "๐ŸŽˆ",  # st.balloons ๐ŸŽˆ๐ŸŽˆ
    "๐Ÿค“",  # Abhi
    "๐Ÿˆ",  # Amey
    "๐Ÿšฒ",  # Thiago
    "๐Ÿง",  # Matteo
    "๐Ÿฆ’",  # Ken
    "๐Ÿณ",  # Karrie
    "๐Ÿ•น๏ธ",  # Jonathan
    "๐Ÿ‡ฆ๐Ÿ‡ฒ",  # Henrikh
    "๐ŸŽธ",  # Guido
    "๐Ÿฆˆ",  # Austin
    "๐Ÿ’Ž",  # Emiliano
    "๐Ÿ‘ฉโ€๐ŸŽค",  # Naomi
    "๐Ÿง™โ€โ™‚๏ธ",  # Jon
    "๐Ÿป",  # Brandon
    "๐ŸŽŽ",  # James
    # TODO: Solicit emojis from the rest of Streamlit
]


def _get_favicon_string(page_icon: PageIcon) -> str:
    """Return the string to pass to the frontend to have it show
    the given PageIcon.

    If page_icon is a string that looks like an emoji (or an emoji shortcode),
    we return it as-is. Otherwise we use `image_to_url` to return a URL.

    (If `image_to_url` raises an error and page_icon is a string, return
    the unmodified page_icon string instead of re-raising the error.)
    """

    # Choose a random emoji.
    if page_icon == "random":
        return get_random_emoji()

    # If page_icon is an emoji, return it as is.
    if isinstance(page_icon, str) and is_emoji(page_icon):
        return page_icon

    if isinstance(page_icon, str) and page_icon.startswith(":material"):
        return validate_material_icon(page_icon)

    # Fall back to image_to_url.
    try:
        return image.image_to_url(
            page_icon,
            width=-1,  # Always use full width for favicons
            clamp=False,
            channels="RGB",
            output_format="auto",
            image_id="favicon",
        )
    except Exception:
        if isinstance(page_icon, str):
            # This fall-thru handles emoji shortcode strings (e.g. ":shark:"),
            # which aren't valid filenames and so will cause an Exception from
            # `image_to_url`.
            return page_icon
        raise


@gather_metrics("set_page_config")
def set_page_config(
    page_title: str | None = None,
    page_icon: PageIcon | None = None,
    layout: Layout = "centered",
    initial_sidebar_state: InitialSideBarState = "auto",
    menu_items: MenuItems | None = None,
) -> None:
    """
    Configures the default settings of the page.

    .. note::
        This must be the first Streamlit command used on an app page, and must only
        be set once per page.

    Parameters
    ----------
    page_title: str or None
        The page title, shown in the browser tab. If None, defaults to the
        filename of the script ("app.py" would show "app โ€ข Streamlit").

    page_icon : Anything supported by st.image, str, or None
        The page favicon. If ``page_icon`` is ``None`` (default), the favicon
        will be a monochrome Streamlit logo.

        In addition to the types supported by ``st.image`` (like URLs or numpy
        arrays), the following strings are valid:

        * A single-character emoji. For example, you can set ``page_icon="๐Ÿฆˆ"``.

        * An emoji short code. For example, you can set ``page_icon=":shark:"``.
          For a list of all supported codes, see
          https://share.streamlit.io/streamlit/emoji-shortcodes.

        * The string literal, ``"random"``. You can set ``page_icon="random"``
          to set a random emoji from the supported list above. Emoji icons are
          courtesy of Twemoji and loaded from MaxCDN.

        * An icon from the Material Symbols library (outlined style) in the
          format ``":material/icon_name:"`` where "icon_name" is the name
          of the icon in snake case.

          For example, ``icon=":material/thumb_up:"`` will display the
          Thumb Up icon. Find additional icons in the `Material Symbols \
          <https://fonts.google.com/icons?icon.set=Material+Symbols&icon.style=Outlined>`_
          font library.

        .. note::
            Colors are not supported for Material icons. When you use a
            Material icon for favicon, it will be black, regardless of browser
            theme.

    layout: "centered" or "wide"
        How the page content should be laid out. Defaults to "centered",
        which constrains the elements into a centered column of fixed width;
        "wide" uses the entire screen.

    initial_sidebar_state: "auto", "expanded", or "collapsed"
        How the sidebar should start out. Defaults to "auto",
        which hides the sidebar on small devices and shows it otherwise.
        "expanded" shows the sidebar initially; "collapsed" hides it.
        In most cases, you should just use "auto", otherwise the app will
        look bad when embedded and viewed on mobile.

    menu_items: dict
        Configure the menu that appears on the top-right side of this app.
        The keys in this dict denote the menu item you'd like to configure:

        - "Get help": str or None
            The URL this menu item should point to.
            If None, hides this menu item.
        - "Report a Bug": str or None
            The URL this menu item should point to.
            If None, hides this menu item.
        - "About": str or None
            A markdown string to show in the About dialog.
            If None, only shows Streamlit's default About text.

        The URL may also refer to an email address e.g. ``mailto:john@example.com``.

    Example
    -------
    >>> import streamlit as st
    >>>
    >>> st.set_page_config(
    ...     page_title="Ex-stream-ly Cool App",
    ...     page_icon="๐ŸงŠ",
    ...     layout="wide",
    ...     initial_sidebar_state="expanded",
    ...     menu_items={
    ...         'Get Help': 'https://www.extremelycoolapp.com/help',
    ...         'Report a bug': "https://www.extremelycoolapp.com/bug",
    ...         'About': "# This is a header. This is an *extremely* cool app!"
    ...     }
    ... )
    """

    msg = ForwardProto()

    if page_title is not None:
        msg.page_config_changed.title = page_title

    if page_icon is not None:
        msg.page_config_changed.favicon = _get_favicon_string(page_icon)

    pb_layout: PageConfigProto.Layout.ValueType
    if layout == "centered":
        pb_layout = PageConfigProto.CENTERED
    elif layout == "wide":
        pb_layout = PageConfigProto.WIDE
    else:
        raise StreamlitAPIException(
            f'`layout` must be "centered" or "wide" (got "{layout}")'
        )
    msg.page_config_changed.layout = pb_layout

    pb_sidebar_state: PageConfigProto.SidebarState.ValueType
    if initial_sidebar_state == "auto":
        pb_sidebar_state = PageConfigProto.AUTO
    elif initial_sidebar_state == "expanded":
        pb_sidebar_state = PageConfigProto.EXPANDED
    elif initial_sidebar_state == "collapsed":
        pb_sidebar_state = PageConfigProto.COLLAPSED
    else:
        raise StreamlitAPIException(
            "`initial_sidebar_state` must be "
            '"auto" or "expanded" or "collapsed" '
            f'(got "{initial_sidebar_state}")'
        )

    msg.page_config_changed.initial_sidebar_state = pb_sidebar_state

    if menu_items is not None:
        lowercase_menu_items = cast(MenuItems, lower_clean_dict_keys(menu_items))
        validate_menu_items(lowercase_menu_items)
        menu_items_proto = msg.page_config_changed.menu_items
        set_menu_items_proto(lowercase_menu_items, menu_items_proto)

    ctx = get_script_run_ctx()
    if ctx is None:
        return
    ctx.enqueue(msg)


def get_random_emoji() -> str:
    # Weigh our emojis 10x, cuz we're awesome!
    # TODO: fix the random seed with a hash of the user's app code, for stability?
    return random.choice(RANDOM_EMOJIS + 10 * ENG_EMOJIS)


def set_menu_items_proto(lowercase_menu_items, menu_items_proto) -> None:
    if GET_HELP_KEY in lowercase_menu_items:
        if lowercase_menu_items[GET_HELP_KEY] is not None:
            menu_items_proto.get_help_url = lowercase_menu_items[GET_HELP_KEY]
        else:
            menu_items_proto.hide_get_help = True

    if REPORT_A_BUG_KEY in lowercase_menu_items:
        if lowercase_menu_items[REPORT_A_BUG_KEY] is not None:
            menu_items_proto.report_a_bug_url = lowercase_menu_items[REPORT_A_BUG_KEY]
        else:
            menu_items_proto.hide_report_a_bug = True

    if ABOUT_KEY in lowercase_menu_items:
        if lowercase_menu_items[ABOUT_KEY] is not None:
            menu_items_proto.about_section_md = dedent(lowercase_menu_items[ABOUT_KEY])


def validate_menu_items(menu_items: MenuItems) -> None:
    for k, v in menu_items.items():
        if not valid_menu_item_key(k):
            raise StreamlitAPIException(
                "We only accept the keys: "
                '"Get help", "Report a bug", and "About" '
                f'("{k}" is not a valid key.)'
            )
        if v is not None and (
            not is_url(v, ("http", "https", "mailto")) and k != ABOUT_KEY
        ):
            raise StreamlitAPIException(f'"{v}" is a not a valid URL!')


def valid_menu_item_key(key: str) -> TypeGuard[MenuKey]:
    return key in {GET_HELP_KEY, REPORT_A_BUG_KEY, ABOUT_KEY}
Back to Directory File Manager