Merging PR_218 openai_rev package with new streamlit chat app
This commit is contained in:
404
venv/lib/python3.9/site-packages/streamlit/web/bootstrap.py
Normal file
404
venv/lib/python3.9/site-packages/streamlit/web/bootstrap.py
Normal file
@@ -0,0 +1,404 @@
|
||||
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022)
|
||||
#
|
||||
# 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.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
import click
|
||||
|
||||
from streamlit import (
|
||||
config,
|
||||
env_util,
|
||||
file_util,
|
||||
net_util,
|
||||
secrets,
|
||||
url_util,
|
||||
util,
|
||||
version,
|
||||
)
|
||||
from streamlit.config import CONFIG_FILENAMES
|
||||
from streamlit.git_util import MIN_GIT_VERSION, GitRepo
|
||||
from streamlit.logger import get_logger
|
||||
from streamlit.source_util import invalidate_pages_cache
|
||||
from streamlit.watcher import report_watchdog_availability, watch_dir, watch_file
|
||||
from streamlit.web.server import Server, server_address_is_unix_socket, server_util
|
||||
|
||||
LOGGER = get_logger(__name__)
|
||||
|
||||
NEW_VERSION_TEXT = """
|
||||
%(new_version)s
|
||||
|
||||
See what's new at https://discuss.streamlit.io/c/announcements
|
||||
|
||||
Enter the following command to upgrade:
|
||||
%(prompt)s %(command)s
|
||||
""" % {
|
||||
"new_version": click.style(
|
||||
"A new version of Streamlit is available.", fg="blue", bold=True
|
||||
),
|
||||
"prompt": click.style("$", fg="blue"),
|
||||
"command": click.style("pip install streamlit --upgrade", bold=True),
|
||||
}
|
||||
|
||||
# The maximum possible total size of a static directory.
|
||||
# We agreed on these limitations for the initial release of static file sharing,
|
||||
# based on security concerns from the SiS and Community Cloud teams
|
||||
MAX_APP_STATIC_FOLDER_SIZE = 1 * 1024 * 1024 * 1024 # 1 GB
|
||||
|
||||
|
||||
def _set_up_signal_handler(server: Server) -> None:
|
||||
LOGGER.debug("Setting up signal handler")
|
||||
|
||||
def signal_handler(signal_number, stack_frame):
|
||||
# The server will shut down its threads and exit its loop.
|
||||
server.stop()
|
||||
|
||||
signal.signal(signal.SIGTERM, signal_handler)
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
if sys.platform == "win32":
|
||||
signal.signal(signal.SIGBREAK, signal_handler)
|
||||
else:
|
||||
signal.signal(signal.SIGQUIT, signal_handler)
|
||||
|
||||
|
||||
def _fix_sys_path(main_script_path: str) -> None:
|
||||
"""Add the script's folder to the sys path.
|
||||
|
||||
Python normally does this automatically, but since we exec the script
|
||||
ourselves we need to do it instead.
|
||||
"""
|
||||
sys.path.insert(0, os.path.dirname(main_script_path))
|
||||
|
||||
|
||||
def _fix_matplotlib_crash() -> None:
|
||||
"""Set Matplotlib backend to avoid a crash.
|
||||
|
||||
The default Matplotlib backend crashes Python on OSX when run on a thread
|
||||
that's not the main thread, so here we set a safer backend as a fix.
|
||||
Users can always disable this behavior by setting the config
|
||||
runner.fixMatplotlib = false.
|
||||
|
||||
This fix is OS-independent. We didn't see a good reason to make this
|
||||
Mac-only. Consistency within Streamlit seemed more important.
|
||||
"""
|
||||
if config.get_option("runner.fixMatplotlib"):
|
||||
try:
|
||||
# TODO: a better option may be to set
|
||||
# os.environ["MPLBACKEND"] = "Agg". We'd need to do this towards
|
||||
# the top of __init__.py, before importing anything that imports
|
||||
# pandas (which imports matplotlib). Alternately, we could set
|
||||
# this environment variable in a new entrypoint defined in
|
||||
# setup.py. Both of these introduce additional trickiness: they
|
||||
# need to run without consulting streamlit.config.get_option,
|
||||
# because this would import streamlit, and therefore matplotlib.
|
||||
import matplotlib
|
||||
|
||||
matplotlib.use("Agg")
|
||||
except ImportError:
|
||||
# Matplotlib is not installed. No need to do anything.
|
||||
pass
|
||||
|
||||
|
||||
def _fix_tornado_crash() -> None:
|
||||
"""Set default asyncio policy to be compatible with Tornado 6.
|
||||
|
||||
Tornado 6 (at least) is not compatible with the default
|
||||
asyncio implementation on Windows. So here we
|
||||
pick the older SelectorEventLoopPolicy when the OS is Windows
|
||||
if the known-incompatible default policy is in use.
|
||||
|
||||
This has to happen as early as possible to make it a low priority and
|
||||
overridable
|
||||
|
||||
See: https://github.com/tornadoweb/tornado/issues/2608
|
||||
|
||||
FIXME: if/when tornado supports the defaults in asyncio,
|
||||
remove and bump tornado requirement for py38
|
||||
"""
|
||||
if env_util.IS_WINDOWS and sys.version_info >= (3, 8):
|
||||
try:
|
||||
from asyncio import ( # type: ignore[attr-defined]
|
||||
WindowsProactorEventLoopPolicy,
|
||||
WindowsSelectorEventLoopPolicy,
|
||||
)
|
||||
except ImportError:
|
||||
pass
|
||||
# Not affected
|
||||
else:
|
||||
if type(asyncio.get_event_loop_policy()) is WindowsProactorEventLoopPolicy:
|
||||
# WindowsProactorEventLoopPolicy is not compatible with
|
||||
# Tornado 6 fallback to the pre-3.8 default of Selector
|
||||
asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy())
|
||||
|
||||
|
||||
def _fix_sys_argv(main_script_path: str, args: List[str]) -> None:
|
||||
"""sys.argv needs to exclude streamlit arguments and parameters
|
||||
and be set to what a user's script may expect.
|
||||
"""
|
||||
import sys
|
||||
|
||||
sys.argv = [main_script_path] + list(args)
|
||||
|
||||
|
||||
def _on_server_start(server: Server) -> None:
|
||||
_maybe_print_old_git_warning(server.main_script_path)
|
||||
_maybe_print_static_folder_warning(server.main_script_path)
|
||||
_print_url(server.is_running_hello)
|
||||
report_watchdog_availability()
|
||||
_print_new_version_message()
|
||||
|
||||
# Load secrets.toml if it exists. If the file doesn't exist, this
|
||||
# function will return without raising an exception. We catch any parse
|
||||
# errors and display them here.
|
||||
try:
|
||||
secrets.load_if_toml_exists()
|
||||
except Exception as ex:
|
||||
LOGGER.error(f"Failed to load secrets.toml file", exc_info=ex)
|
||||
|
||||
def maybe_open_browser():
|
||||
if config.get_option("server.headless"):
|
||||
# Don't open browser when in headless mode.
|
||||
return
|
||||
|
||||
if config.is_manually_set("browser.serverAddress"):
|
||||
addr = config.get_option("browser.serverAddress")
|
||||
elif config.is_manually_set("server.address"):
|
||||
if server_address_is_unix_socket():
|
||||
# Don't open browser when server address is an unix socket
|
||||
return
|
||||
addr = config.get_option("server.address")
|
||||
else:
|
||||
addr = "localhost"
|
||||
|
||||
util.open_browser(server_util.get_url(addr))
|
||||
|
||||
# Schedule the browser to open on the main thread.
|
||||
asyncio.get_running_loop().call_soon(maybe_open_browser)
|
||||
|
||||
|
||||
def _fix_pydeck_mapbox_api_warning() -> None:
|
||||
"""Sets MAPBOX_API_KEY environment variable needed for PyDeck otherwise it will throw an exception"""
|
||||
|
||||
os.environ["MAPBOX_API_KEY"] = config.get_option("mapbox.token")
|
||||
|
||||
|
||||
def _print_new_version_message() -> None:
|
||||
if version.should_show_new_version_notice():
|
||||
click.secho(NEW_VERSION_TEXT)
|
||||
|
||||
|
||||
def _maybe_print_static_folder_warning(main_script_path: str) -> None:
|
||||
"""Prints a warning if the static folder is misconfigured."""
|
||||
|
||||
if config.get_option("server.enableStaticServing"):
|
||||
static_folder_path = file_util.get_app_static_dir(main_script_path)
|
||||
if not os.path.isdir(static_folder_path):
|
||||
click.secho(
|
||||
f"WARNING: Static file serving is enabled, but no static folder found "
|
||||
f"at {static_folder_path}. To disable static file serving, "
|
||||
f"set server.enableStaticServing to false.",
|
||||
fg="yellow",
|
||||
)
|
||||
else:
|
||||
# Raise warning when static folder size is larger than 1 GB
|
||||
static_folder_size = file_util.get_directory_size(static_folder_path)
|
||||
|
||||
if static_folder_size > MAX_APP_STATIC_FOLDER_SIZE:
|
||||
config.set_option("server.enableStaticServing", False)
|
||||
click.secho(
|
||||
"WARNING: Static folder size is larger than 1GB. "
|
||||
"Static file serving has been disabled.",
|
||||
fg="yellow",
|
||||
)
|
||||
|
||||
|
||||
def _print_url(is_running_hello: bool) -> None:
|
||||
if is_running_hello:
|
||||
title_message = "Welcome to Streamlit. Check out our demo in your browser."
|
||||
else:
|
||||
title_message = "You can now view your Streamlit app in your browser."
|
||||
|
||||
named_urls = []
|
||||
|
||||
if config.is_manually_set("browser.serverAddress"):
|
||||
named_urls = [
|
||||
("URL", server_util.get_url(config.get_option("browser.serverAddress")))
|
||||
]
|
||||
|
||||
elif (
|
||||
config.is_manually_set("server.address") and not server_address_is_unix_socket()
|
||||
):
|
||||
named_urls = [
|
||||
("URL", server_util.get_url(config.get_option("server.address"))),
|
||||
]
|
||||
|
||||
elif server_address_is_unix_socket():
|
||||
named_urls = [
|
||||
("Unix Socket", config.get_option("server.address")),
|
||||
]
|
||||
|
||||
elif config.get_option("server.headless"):
|
||||
internal_ip = net_util.get_internal_ip()
|
||||
if internal_ip:
|
||||
named_urls.append(("Network URL", server_util.get_url(internal_ip)))
|
||||
|
||||
external_ip = net_util.get_external_ip()
|
||||
if external_ip:
|
||||
named_urls.append(("External URL", server_util.get_url(external_ip)))
|
||||
|
||||
else:
|
||||
named_urls = [
|
||||
("Local URL", server_util.get_url("localhost")),
|
||||
]
|
||||
|
||||
internal_ip = net_util.get_internal_ip()
|
||||
if internal_ip:
|
||||
named_urls.append(("Network URL", server_util.get_url(internal_ip)))
|
||||
|
||||
click.secho("")
|
||||
click.secho(" %s" % title_message, fg="blue", bold=True)
|
||||
click.secho("")
|
||||
|
||||
for url_name, url in named_urls:
|
||||
url_util.print_url(url_name, url)
|
||||
|
||||
click.secho("")
|
||||
|
||||
if is_running_hello:
|
||||
click.secho(" Ready to create your own Python apps super quickly?")
|
||||
click.secho(" Head over to ", nl=False)
|
||||
click.secho("https://docs.streamlit.io", bold=True)
|
||||
click.secho("")
|
||||
click.secho(" May you create awesome apps!")
|
||||
click.secho("")
|
||||
click.secho("")
|
||||
|
||||
|
||||
def _maybe_print_old_git_warning(main_script_path: str) -> None:
|
||||
"""If our script is running in a Git repo, and we're running a very old
|
||||
Git version, print a warning that Git integration will be unavailable.
|
||||
"""
|
||||
repo = GitRepo(main_script_path)
|
||||
if (
|
||||
not repo.is_valid()
|
||||
and repo.git_version is not None
|
||||
and repo.git_version < MIN_GIT_VERSION
|
||||
):
|
||||
git_version_string = ".".join(str(val) for val in repo.git_version)
|
||||
min_version_string = ".".join(str(val) for val in MIN_GIT_VERSION)
|
||||
click.secho("")
|
||||
click.secho(" Git integration is disabled.", fg="yellow", bold=True)
|
||||
click.secho("")
|
||||
click.secho(
|
||||
f" Streamlit requires Git {min_version_string} or later, "
|
||||
f"but you have {git_version_string}.",
|
||||
fg="yellow",
|
||||
)
|
||||
click.secho(
|
||||
" Git is used by Streamlit Cloud (https://streamlit.io/cloud).",
|
||||
fg="yellow",
|
||||
)
|
||||
click.secho(" To enable this feature, please update Git.", fg="yellow")
|
||||
|
||||
|
||||
def load_config_options(flag_options: Dict[str, Any]) -> None:
|
||||
"""Load config options from config.toml files, then overlay the ones set by
|
||||
flag_options.
|
||||
|
||||
The "streamlit run" command supports passing Streamlit's config options
|
||||
as flags. This function reads through the config options set via flag,
|
||||
massages them, and passes them to get_config_options() so that they
|
||||
overwrite config option defaults and those loaded from config.toml files.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
flag_options : Dict[str, Any]
|
||||
A dict of config options where the keys are the CLI flag version of the
|
||||
config option names.
|
||||
"""
|
||||
options_from_flags = {
|
||||
name.replace("_", "."): val
|
||||
for name, val in flag_options.items()
|
||||
if val is not None
|
||||
}
|
||||
|
||||
# Force a reparse of config files (if they exist). The result is cached
|
||||
# for future calls.
|
||||
config.get_config_options(force_reparse=True, options_from_flags=options_from_flags)
|
||||
|
||||
|
||||
def _install_config_watchers(flag_options: Dict[str, Any]) -> None:
|
||||
def on_config_changed(_path):
|
||||
load_config_options(flag_options)
|
||||
|
||||
for filename in CONFIG_FILENAMES:
|
||||
if os.path.exists(filename):
|
||||
watch_file(filename, on_config_changed)
|
||||
|
||||
|
||||
def _install_pages_watcher(main_script_path_str: str) -> None:
|
||||
def _on_pages_changed(_path: str) -> None:
|
||||
invalidate_pages_cache()
|
||||
|
||||
main_script_path = Path(main_script_path_str)
|
||||
pages_dir = main_script_path.parent / "pages"
|
||||
|
||||
watch_dir(
|
||||
str(pages_dir),
|
||||
_on_pages_changed,
|
||||
glob_pattern="*.py",
|
||||
allow_nonexistent=True,
|
||||
)
|
||||
|
||||
|
||||
def run(
|
||||
main_script_path: str,
|
||||
command_line: Optional[str],
|
||||
args: List[str],
|
||||
flag_options: Dict[str, Any],
|
||||
) -> None:
|
||||
"""Run a script in a separate thread and start a server for the app.
|
||||
|
||||
This starts a blocking asyncio eventloop.
|
||||
"""
|
||||
_fix_sys_path(main_script_path)
|
||||
_fix_matplotlib_crash()
|
||||
_fix_tornado_crash()
|
||||
_fix_sys_argv(main_script_path, args)
|
||||
_fix_pydeck_mapbox_api_warning()
|
||||
_install_config_watchers(flag_options)
|
||||
_install_pages_watcher(main_script_path)
|
||||
|
||||
# Create the server. It won't start running yet.
|
||||
server = Server(main_script_path, command_line)
|
||||
|
||||
async def run_server() -> None:
|
||||
# Start the server
|
||||
await server.start()
|
||||
_on_server_start(server)
|
||||
|
||||
# Install a signal handler that will shut down the server
|
||||
# and close all our threads
|
||||
_set_up_signal_handler(server)
|
||||
|
||||
# Wait until `Server.stop` is called, either by our signal handler, or
|
||||
# by a debug websocket session.
|
||||
await server.stopped
|
||||
|
||||
# Run the server. This function will not return until the server is shut down.
|
||||
asyncio.run(run_server())
|
||||
Reference in New Issue
Block a user