184 lines
6.1 KiB
Python
184 lines
6.1 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 re
|
||
|
|
||
|
from streamlit import cli_util
|
||
|
from streamlit.config_option import ConfigOption
|
||
|
|
||
|
|
||
|
def server_option_changed(
|
||
|
old_options: dict[str, ConfigOption], new_options: dict[str, ConfigOption]
|
||
|
) -> bool:
|
||
|
"""Return True if and only if an option in the server section differs
|
||
|
between old_options and new_options.
|
||
|
"""
|
||
|
for opt_name, opt_val in old_options.items():
|
||
|
if not opt_name.startswith("server"):
|
||
|
continue
|
||
|
|
||
|
old_val = opt_val.value
|
||
|
new_val = new_options[opt_name].value
|
||
|
if old_val != new_val:
|
||
|
return True
|
||
|
|
||
|
return False
|
||
|
|
||
|
|
||
|
def show_config(
|
||
|
section_descriptions: dict[str, str],
|
||
|
config_options: dict[str, ConfigOption],
|
||
|
) -> None:
|
||
|
"""Print the given config sections/options to the terminal."""
|
||
|
|
||
|
out = []
|
||
|
out.append(
|
||
|
_clean(
|
||
|
"""
|
||
|
# Below are all the sections and options you can have in
|
||
|
~/.streamlit/config.toml.
|
||
|
"""
|
||
|
)
|
||
|
)
|
||
|
|
||
|
def append_desc(text: str) -> None:
|
||
|
out.append("# " + cli_util.style_for_cli(text, bold=True))
|
||
|
|
||
|
def append_comment(text: str) -> None:
|
||
|
out.append("# " + cli_util.style_for_cli(text))
|
||
|
|
||
|
def append_section(text: str) -> None:
|
||
|
out.append(cli_util.style_for_cli(text, bold=True, fg="green"))
|
||
|
|
||
|
def append_setting(text: str) -> None:
|
||
|
out.append(cli_util.style_for_cli(text, fg="green"))
|
||
|
|
||
|
for section in section_descriptions:
|
||
|
# We inject a fake config section used for unit tests that we exclude here as
|
||
|
# its options are often missing required properties, which confuses the code
|
||
|
# below.
|
||
|
if section == "_test":
|
||
|
continue
|
||
|
|
||
|
section_options = {
|
||
|
k: v
|
||
|
for k, v in config_options.items()
|
||
|
if v.section == section and v.visibility == "visible" and not v.is_expired()
|
||
|
}
|
||
|
|
||
|
# Only show config header if section is non-empty.
|
||
|
if len(section_options) == 0:
|
||
|
continue
|
||
|
|
||
|
out.append("")
|
||
|
append_section(f"[{section}]")
|
||
|
out.append("")
|
||
|
|
||
|
for option in section_options.values():
|
||
|
key = option.key.split(".")[-1]
|
||
|
description_paragraphs = _clean_paragraphs(option.description or "")
|
||
|
|
||
|
last_paragraph_idx = len(description_paragraphs) - 1
|
||
|
|
||
|
for i, paragraph in enumerate(description_paragraphs):
|
||
|
# Split paragraph into lines
|
||
|
lines = paragraph.rstrip().split(
|
||
|
"\n"
|
||
|
) # Remove trailing newline characters
|
||
|
|
||
|
# If the first line is empty, remove it
|
||
|
if lines and not lines[0].strip():
|
||
|
lines = lines[1:]
|
||
|
|
||
|
# Choose function based on whether it's the first paragraph or not
|
||
|
append_func = append_desc if i == 0 else append_comment
|
||
|
|
||
|
# Add comment character to each line and add to out
|
||
|
for line in lines:
|
||
|
append_func(line.lstrip())
|
||
|
|
||
|
# # Add a line break after a paragraph only if it's not the last paragraph
|
||
|
if i != last_paragraph_idx:
|
||
|
append_comment("")
|
||
|
|
||
|
if option.deprecated:
|
||
|
if out[-1] != "#":
|
||
|
append_comment("")
|
||
|
append_comment(
|
||
|
cli_util.style_for_cli("THIS IS DEPRECATED.", fg="yellow")
|
||
|
)
|
||
|
append_comment("")
|
||
|
for line in _clean_paragraphs(option.deprecation_text):
|
||
|
append_comment(line)
|
||
|
append_comment("")
|
||
|
append_comment(
|
||
|
f"This option will be removed on or after {option.expiration_date}."
|
||
|
)
|
||
|
|
||
|
import toml
|
||
|
|
||
|
toml_default = toml.dumps({"default": option.default_val})
|
||
|
toml_default = toml_default[10:].strip()
|
||
|
|
||
|
if len(toml_default) > 0:
|
||
|
# Ensure a line break before appending "Default" comment, if not already there
|
||
|
if out[-1] != "#":
|
||
|
append_comment("")
|
||
|
append_comment(f"Default: {toml_default}")
|
||
|
else:
|
||
|
# Don't say "Default: (unset)" here because this branch applies
|
||
|
# to complex config settings too.
|
||
|
pass
|
||
|
|
||
|
option_is_manually_set = (
|
||
|
option.where_defined != ConfigOption.DEFAULT_DEFINITION
|
||
|
)
|
||
|
|
||
|
if option_is_manually_set:
|
||
|
if out[-1] != "# ":
|
||
|
append_comment("")
|
||
|
append_comment(f"The value below was set in {option.where_defined}")
|
||
|
|
||
|
toml_setting = toml.dumps({key: option.value})
|
||
|
|
||
|
if len(toml_setting) == 0:
|
||
|
toml_setting = f"# {key} =\n"
|
||
|
elif not option_is_manually_set:
|
||
|
toml_setting = f"# {toml_setting}"
|
||
|
|
||
|
append_setting(toml_setting)
|
||
|
|
||
|
cli_util.print_to_cli("\n".join(out))
|
||
|
|
||
|
|
||
|
def _clean(txt: str) -> str:
|
||
|
"""Replace sequences of multiple spaces with a single space, excluding newlines.
|
||
|
|
||
|
Preserves leading and trailing spaces, and does not modify spaces in between lines.
|
||
|
"""
|
||
|
return re.sub(" +", " ", txt)
|
||
|
|
||
|
|
||
|
def _clean_paragraphs(txt: str) -> list[str]:
|
||
|
"""Split the text into paragraphs, preserve newlines within the paragraphs."""
|
||
|
# Strip both leading and trailing newlines.
|
||
|
txt = txt.strip("\n")
|
||
|
paragraphs = txt.split("\n\n")
|
||
|
return [
|
||
|
"\n".join(_clean(line) for line in paragraph.split("\n"))
|
||
|
for paragraph in paragraphs
|
||
|
]
|