ui command: remove required dependency on streamlit (#1141)
Run Link Checker for Cron Job / markdown-link-check (push) Has been cancelled
Run Smoke Test / configuration (push) Has been cancelled
Run CI Pipeline for ScubaGoggles / Pylint (push) Has been cancelled
Run CI Pipeline for ScubaGoggles / Run OPA Tests (push) Has been cancelled
Run CI Pipeline for ScubaGoggles / Run Markdown Link Check (push) Has been cancelled
Run CI Pipeline for ScubaGoggles / Run Python Tests (push) Has been cancelled
Run Smoke Test / smoke-test (push) Has been cancelled
Run Smoke Test / lhci (push) Has been cancelled

ui launch: use config options to silence streamlit; change streamlit install command
pyproject: use optional dependencies to install UI packages
update unit tests for UI changes
This commit is contained in:
Roy Lane authored and GitHub committed 2026-07-28 09:36:55 -04:00
1 parent 8479d7c52b
commit 65d4e287ce
8 files changed
+57 -69

No files matched your search

+18 -5
View File
@@ -76,14 +76,27 @@ running ScubaGoggles.
> [!NOTE]
> If you are interested in contributing to ScubaGoggles or for any reason need to install the latest development code, please see the [Development Guide](../development/DEVELOPMENTGUIDE.md) for instructions on setting up ScubaGoggles for development. Otherwise, continue with the instructions below.
>
>pip is not installed by default on LinuxOS. If pip is not installed in your environment, please visit [pip website](https://pip.pypa.io/en/stable/installation/) for instructions on how to download and install pip.
>pip may not be installed by default on LinuxOS. If pip is not installed in your environment, please visit [pip website](https://pip.pypa.io/en/stable/installation/) for instructions on how to download and install pip.
To install ScubaGoggles:
1. If you are using a virtual environment, ensure your environment is activated by running the appropriate command from the previous section.
2. Next, run the following command. Depending on your system, you may also need to substitute `pip` with `pip3`.
```
pip install scubagoggles
```
2. Next, run the following command. Depending on your system, you may
also need to substitute `pip` with `pip3`.
```
pip install scubagoggles
```
3. If you want to run the Configuration UI (user interface), use the following
command instead of, or in addition to, the command above to install the
additional packages required by the UI.
```
pip install scubagoggles[ui]
```
*NOTE: if you are installing ScubaGoggles using a downloaded "wheel" file,
add the "[ui]" at the end of the file specification:
`pip install scubagoggles-1.0.0-py3-none-any.whl[ui]`*
At this point, ScubaGoggles will be installed, but additional setup
steps are necessary before it can be used. Continue to [Download the OPA executable](OPA.md)
+3
View File
@@ -30,6 +30,9 @@ license = "CC0-1.0"
license-files = ["LICENSE"]
readme = "README.md"
[project.optional-dependencies]
ui = ["streamlit>=1.35.0"]
[project.scripts]
scubagoggles = "scubagoggles.main:dive"
@@ -397,7 +397,7 @@ class TestMain:
def fake_get_gws_args(parser, _user_config):
parser.set_defaults(dispatch=make_dispatch("gws"))
def fake_get_gws_ui_args(parser, _user_config):
def fake_get_ui_args(parser):
parser.set_defaults(dispatch=make_dispatch("ui"))
def fake_get_opa_args(parser, _user_config):
@@ -413,7 +413,7 @@ class TestMain:
parser.set_defaults(dispatch=make_dispatch("version"))
monkeypatch.setattr(main_module, "get_gws_args", fake_get_gws_args)
monkeypatch.setattr(main_module, "get_gws_ui_args", fake_get_gws_ui_args)
monkeypatch.setattr(main_module, "get_ui_args", fake_get_ui_args)
monkeypatch.setattr(main_module, "get_opa_args", fake_get_opa_args)
monkeypatch.setattr(main_module, "get_purge_args", fake_get_purge_args)
monkeypatch.setattr(main_module, "get_setup_args", fake_get_setup_args)
@@ -69,14 +69,8 @@ class TestLaunch:
# avoid backslashes to bypass OS ambiguity Path to str conversion
app_path = Path('home')
command, port = launch._build_streamlit_command(app_path, force_dark=dark_mode)
expected_cmd = [
str(sys.executable), '-m', 'streamlit', 'run',
'home',
'--server.address', 'localhost',
'--server.port', '1000',
'--server.headless', 'false',
'--browser.gatherUsageStats', 'false',
]
expected_cmd = self._streamlit_command('1000')
# mock return
assert port == 1000
if dark_mode:
@@ -177,20 +171,13 @@ class TestLaunch:
monkeypatch.delenv('SCUBAGOGGLES_UI_DARK', raising=False)
# expected build command
expected_cmd = [
str(sys.executable), '-m', 'streamlit', 'run',
'home',
'--server.address', 'localhost',
'--server.port', '1234',
'--server.headless', 'false',
'--browser.gatherUsageStats', 'false',
]
expected_cmd = self._streamlit_command('1234')
if dark_mode:
expected_cmd.extend(['--theme.base', 'dark'])
# arbitrary return values for mocked functions
mocker.patch.object(launch, '_find_free_port', return_value=1234)
mocker.patch.object(launch, '_get_app_to_run', return_value=Path('home'))
mocker.patch.object(launch, '_prevent_streamlit_promotion')
real_print = builtins.print
mock_print = mocker.patch('builtins.print', side_effect=real_print)
mock_run_server = mocker.patch.object(launch, '_run_server')
@@ -216,3 +203,21 @@ class TestLaunch:
mock_print.assert_any_call('Opening http://localhost:1234 in your browser.')
mock_print.assert_any_call('Press Ctrl+C to stop the server.\n')
mock_run_server.assert_called_once_with(expected_cmd, popen_kwargs)
@staticmethod
def _streamlit_command(port: str) -> str:
"""Builds the list of command arguments for the expected streamlit
command using the given port number.
"""
command = [sys.executable, '-m', 'streamlit', 'run',
'home',
'--server.address', 'localhost',
'--server.port', port,
'--server.headless', 'false',
'--browser.gatherUsageStats', 'false',
'--server.showEmailPrompt', 'false',
'--logger.hideWelcomeMessage', 'true']
return command
+4 -4
View File
@@ -21,7 +21,7 @@ from scubagoggles.scuba_argument_parser import ScubaArgumentParser
from scubagoggles.user_setup import default_file_names, user_setup
from scubagoggles.utils import path_parser
from scubagoggles.version import Version
from scubagoggles.ui import launch
from scubagoggles.ui.launch import launch_from_ui_command as ui_launch
from scubagoggles.scuba_constants import NUMBER_OF_UUID_CHARACTERS_TO_TRUNCATE_CHOICES, OPA_VERSION
EXIT_FAILURE = 1
@@ -282,14 +282,14 @@ def get_gws_args(parser: argparse.ArgumentParser, user_config: UserConfig):
action='store_true',
help=help_msg)
def get_gws_ui_args(parser: argparse.ArgumentParser, user_config: UserConfig): # pylint: disable=unused-argument
def get_ui_args(parser: argparse.ArgumentParser):
"""Adds the arguments for the UI parser
:param argparse.ArgumentParser parser: argparse object
:param UserConfig user_config: user configuration object
"""
parser.set_defaults(dispatch=launch.launch_from_ui_command)
parser.set_defaults(dispatch=ui_launch)
parser.add_argument('--darkmode',
'-dm',
@@ -492,7 +492,7 @@ def dive():
gws_parser = subparsers.add_parser('ui',
description=help_msg,
help=help_msg)
get_gws_ui_args(gws_parser, user_config)
get_ui_args(gws_parser)
help_msg = 'Download OPA executable'
getopa_parser = subparsers.add_parser('getopa',
+3 -3
View File
@@ -60,8 +60,8 @@ The application consolidates all configuration capabilities into a single, profe
### Install Dependencies
```bash
# Install all requirements including UI dependencies (from the ScubaGoggles directory)
pip install -r requirements.txt
# Install the additional UI dependencies
pip install scubagoggles[ui]
```
## Usage
@@ -70,7 +70,7 @@ pip install -r requirements.txt
```bash
# From the ScubaGoggles root directory
scubagoggles ui
scubagoggles ui
```
This will start the Streamlit server and open the app in your default web browser. Dark mode is automatically detected from your browser's preferred color scheme via CSS media queries. It can additionally be specified from the command line by running:
-15
View File
@@ -1,15 +0,0 @@
"""
ScubaGoggles UI Package
Configuration interface for ScubaGoggles using Streamlit
"""
__version__ = "1.0.0"
__author__ = "CISA SCuBA Team"
from .scubaconfigapp import ScubaConfigApp
from .validation import ConfigValidator
__all__ = [
"ScubaConfigApp",
"ConfigValidator",
]
+5 -23
View File
@@ -25,23 +25,6 @@ def _find_free_port() -> int:
s.bind(("localhost", 0))
return s.getsockname()[1]
def _prevent_streamlit_promotion() -> None:
"""Streamlit self-promotes upon initial invocation, which is not
appropriate particularly for this application. It can be avoided by
creating its "credentials" file with an empty email address. This is
only done if the file doesn't already exist.
"""
streamlit_dir = Path('~/.streamlit').expanduser()
streamlit_dir.mkdir(exist_ok=True, parents=True)
streamlit_config = streamlit_dir / 'credentials.toml'
if not streamlit_config.exists():
streamlit_config.write_text('[general]\nemail = ""\n',
encoding='utf-8')
def _resolve_app_file() -> Path | None:
"""Return the path to the Streamlit app file."""
@@ -80,9 +63,9 @@ def _get_app_to_run() -> Path:
print("Please ensure the UI modules are properly installed.")
raise SystemExit(1)
if not _is_streamlit_installed():
print("Streamlit is not installed!")
print("Please install requirements:")
print(" pip install -r requirements.txt")
print("Streamlit is required for the graphical user interface.")
print("Please install using this command (see documentation):")
print(" pip install scubagoggles[ui]")
raise SystemExit(1)
return app_to_run
@@ -101,6 +84,8 @@ def _build_streamlit_command(app_to_run: Path,
"--server.port", str(port),
"--server.headless", "false",
"--browser.gatherUsageStats", "false",
"--server.showEmailPrompt", "false",
"--logger.hideWelcomeMessage", "true"
]
# add extra option if dark option specified on command line
if force_dark:
@@ -143,9 +128,6 @@ def launch_main(darkmode = False) -> None:
cmd, port = _build_streamlit_command(app_to_run, force_dark)
_prevent_streamlit_promotion()
popen_kwargs: dict = {}
if sys.platform != "win32":
# On Unix, start a new session so os.killpg can target the group.