Skip to content

Commit

Permalink
Avoid requiring jupyter_config.py in to be in CYLC_SITE_CONF_PATH/uis…
Browse files Browse the repository at this point in the history
…erver

Remove the need for the uiserver subdirectory.
Ensure that user is warned if file at CYLC_SITE_CONF_PATH is
* Unreadable
* Non-existent
  • Loading branch information
wxtim committed May 9, 2024
1 parent 399ea47 commit 00708ae
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 8 deletions.
1 change: 1 addition & 0 deletions changes.d/594.fix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Avoid requiring jupyter_config.py in to be in uiserver subdirectory when using CYLC_SITE_CONF_PATH
3 changes: 2 additions & 1 deletion cylc/uiserver/config_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
)

# base configuration - always used
DEFAULT_CONF_PATH: Path = Path(uis_pkg).parent / 'jupyter_config.py'
CONF_FILE_NAME = 'jupyter_config.py'
DEFAULT_CONF_PATH: Path = Path(uis_pkg).parent / CONF_FILE_NAME
UISERVER_DIR = 'uiserver'
# UIS configuration dirs
SITE_CONF_ROOT: Path = Path(
Expand Down
26 changes: 21 additions & 5 deletions cylc/uiserver/jupyterhub_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
from pathlib import Path

from cylc.uiserver.config_util import (
CONF_FILE_NAME,
DEFAULT_CONF_PATH,
UISERVER_DIR,
USER_CONF_ROOT,
SITE_CONF_ROOT,
get_conf_dir_hierarchy
Expand All @@ -46,10 +46,8 @@ def _load(path):
def load() -> None:
"""Load the relevant UIS/Hub configuration files."""
if os.getenv('CYLC_SITE_CONF_PATH'):
site_conf_path: Path = Path(
os.environ['CYLC_SITE_CONF_PATH'],
UISERVER_DIR
)
site_conf_path: Path = check_cylc_site_conf_path(
Path(os.environ['CYLC_SITE_CONF_PATH']))
else:
site_conf_path = SITE_CONF_ROOT
base_config_paths = [site_conf_path, USER_CONF_ROOT]
Expand All @@ -61,6 +59,24 @@ def load() -> None:
_load(Path(path))


def check_cylc_site_conf_path(path_: Path) -> Path:
"""Check path set by CYLC_SITE_CONF_PATH
1. Path exists and has a file.
2. File is readable.
"""
conf_file_path = (path_ / CONF_FILE_NAME)
if not conf_file_path.is_file():
LOG.warning(
f'Config path {path_} set by'
' "CYLC_SITE_CONF_PATH" does not exist or.'
' does not have a jupyter_config.py file.')
elif not os.access(conf_file_path, os.R_OK):
LOG.error(f'Unable to read config file at {path_}')
return SITE_CONF_ROOT
return path_


hub_version = os.environ.get('CYLC_HUB_VERSION')
if hub_version:
# auto-load the config (jupyterhub requirement)
Expand Down
4 changes: 2 additions & 2 deletions cylc/uiserver/tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ def test_cylc_site_conf_path(clear_env, capload, monkeypatch):
load()
assert capload == [
SYS_CONF,
Path('elephant/uiserver/jupyter_config.py'),
Path('elephant/uiserver/0/jupyter_config.py'),
Path('elephant/jupyter_config.py'),
Path('elephant/0/jupyter_config.py'),
Path(USER_CONF / 'jupyter_config.py'),
Path(USER_CONF / '0/jupyter_config.py')
]
Expand Down
39 changes: 39 additions & 0 deletions cylc/uiserver/tests/test_jupyterhub_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Tests for jupyterhub_config module."""

from cylc.uiserver.jupyterhub_config import check_cylc_site_conf_path
from cylc.uiserver.config_util import CONF_FILE_NAME, SITE_CONF_ROOT


def test_cylc_site_conf_path_ok(tmp_path, caplog):
"""Method passes valid file without comment"""
(tmp_path / CONF_FILE_NAME).touch()
assert check_cylc_site_conf_path(tmp_path) == tmp_path
assert caplog.messages == []


def test_cylc_site_conf_path_unreadable(tmp_path, caplog):
"""Method logs error because file exists but is unreadable."""
(tmp_path / CONF_FILE_NAME).touch()
(tmp_path / CONF_FILE_NAME).chmod(0)
assert check_cylc_site_conf_path(tmp_path) == SITE_CONF_ROOT
assert caplog.messages[0].startswith('Unable to read config file at')


def test_cylc_site_conf_path_empty(tmp_path, caplog):
"""Method logs error because file does not exist."""
assert check_cylc_site_conf_path(tmp_path) == tmp_path
assert 'does not exist' in caplog.messages[0]

0 comments on commit 00708ae

Please sign in to comment.