Skip to content

Commit 2dfc9f8

Browse files
authored
Merge pull request #232 from CABLE-LSM/231-optional-project-keyword-config
`project` keyword improvements in `config.yml`
2 parents 77ea2ad + e3f1f9e commit 2dfc9f8

10 files changed

Lines changed: 234 additions & 61 deletions

File tree

benchcab/benchcab.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,21 @@ def _validate_environment(self, project: str, modules: list):
6464
)
6565
sys.exit(1)
6666

67-
required_groups = [project, "ks32", "hh5"]
67+
if project is None:
68+
msg = """Couldn't resolve project: check 'project' in config.yaml
69+
and/or $PROJECT set in ~/.config/gadi-login.conf
70+
"""
71+
raise AttributeError(msg)
72+
73+
required_groups = set([project, "ks32", "hh5"])
6874
groups = [grp.getgrgid(gid).gr_name for gid in os.getgroups()]
69-
if not set(required_groups).issubset(groups):
70-
print(
71-
"Error: user does not have the required group permissions.",
72-
"The required groups are:",
73-
", ".join(required_groups),
75+
if not required_groups.issubset(groups):
76+
msg = (
77+
f"""Error: user does not have the required group permissions.,
78+
The required groups are:,
79+
{", ".join(required_groups)}""",
7480
)
75-
sys.exit(1)
81+
raise PermissionError(msg)
7682

7783
for modname in modules:
7884
if not self.modules_handler.module_is_avail(modname):

benchcab/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# SPDX-License-Identifier: Apache-2.0
33

44
"""A module containing all *_config() functions."""
5+
import os
56
from pathlib import Path
67

78
import yaml
@@ -81,6 +82,9 @@ def read_optional_key(config: dict):
8182
config : dict
8283
The configuration file with with/without optional keys
8384
"""
85+
if "project" not in config:
86+
config["project"] = os.environ.get("PROJECT", None)
87+
8488
if "realisations" in config:
8589
for r in config["realisations"]:
8690
r["name"] = r.get("name")

benchcab/data/config-schema.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
project:
22
type: "string"
3+
required: false
34

45
modules:
56
type: "list"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#
1616
# Strings can be given with or without double or single quotes.
1717

18-
project: w97
18+
# Uses minimal set of parameters required to run benchcab
1919

2020
realisations:
2121
- repo:

benchcab/data/test/config-invalid.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# A sample configuration that should fail validation.
2-
project: w97
32

43
fluxsite:
54
experiment: NON EXISTENT EXPERIMENT!!!
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Config with optional data
2+
project: hh5
3+
4+
fluxsite:
5+
experiment: AU-Tum
6+
multiprocess: False
7+
pbs:
8+
ncpus: 6
9+
mem: 10GB
10+
walltime: "10:00:00"
11+
storage:
12+
- scratch/$PROJECT
13+
14+
science_configurations:
15+
- cable:
16+
cable_user:
17+
GS_SWITCH: "test_gs"
18+
FWSOIL_SWITCH: "test_fw"
19+
20+
realisations:
21+
- repo:
22+
svn:
23+
branch_path: trunk
24+
name: svn_trunk
25+
- repo:
26+
svn:
27+
branch_path: branches/Users/ccc561/v3.0-YP-changes
28+
name: git_branch
29+
30+
31+
modules: [
32+
intel-compiler/2021.1.1,
33+
netcdf/4.7.4,
34+
openmpi/4.1.0
35+
]

benchcab/internal.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
_, NODENAME, _, _, _ = os.uname()
1212

13-
CONFIG_REQUIRED_KEYS = ["realisations", "project", "modules", "experiment"]
13+
CONFIG_REQUIRED_KEYS = ["realisations", "modules"]
1414

1515
# Parameters for job script:
1616
QSUB_FNAME = "benchmark_cable_qsub.sh"

docs/user_guide/config_options.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ The different running modes of `benchcab` are solely dependent on the options us
3232

3333
## project
3434

35-
: **Default:** _required key, no default_. :octicons-dash-24: NCI project ID to charge the simulations to.
35+
: **Default:** user's default project, _optional key_. :octicons-dash-24: NCI project ID to charge the simulations to. The user's default project defined in the $PROJECT environment variable is used by default.
3636

3737
``` yaml
3838

tests/test_benchcab.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
"""`pytest` tests for `benchcab.py`."""
2+
import re
3+
from contextlib import nullcontext as does_not_raise
4+
from unittest import mock
5+
6+
import pytest
7+
8+
from benchcab.benchcab import Benchcab
9+
10+
11+
@pytest.fixture(scope="module", autouse=True)
12+
def _set_user_projects():
13+
with mock.patch("grp.getgrgid") as mocked_getgrid, mock.patch(
14+
"os.getgroups"
15+
) as mocked_groups:
16+
type(mocked_getgrid.return_value).gr_name = mock.PropertyMock(
17+
return_value="hh5"
18+
)
19+
mocked_groups.return_value = [1]
20+
yield
21+
22+
23+
@pytest.fixture(scope="module", params=["hh5", "invalid_project_name"])
24+
def config_project(request):
25+
"""Get config project name."""
26+
return request.param
27+
28+
29+
# Error message if config project name cannot be resolved.
30+
no_project_name_msg = re.escape(
31+
"""Couldn't resolve project: check 'project' in config.yaml
32+
and/or $PROJECT set in ~/.config/gadi-login.conf
33+
"""
34+
)
35+
36+
# For testing whether user is member of necessary projects to run benchcab, we need to simulate the environment of Gadi
37+
# TODO: Simulate Gadi environment for running tests for validating environment
38+
39+
40+
@pytest.mark.skip()
41+
@pytest.mark.parametrize(
42+
("config_project", "pytest_error"),
43+
[
44+
("hh5", does_not_raise()),
45+
(None, pytest.raises(AttributeError, match=no_project_name_msg)),
46+
],
47+
)
48+
def test_project_name(config_project, pytest_error):
49+
"""Tests whether config project name is suitable to run in Gadi environment."""
50+
app = Benchcab(benchcab_exe_path=None)
51+
with pytest_error:
52+
app._validate_environment(project=config_project, modules=[])
53+
54+
55+
@pytest.mark.skip()
56+
@pytest.mark.parametrize(
57+
("config_project", "pytest_error"),
58+
[
59+
("hh5", does_not_raise()),
60+
("invalid_project_name", pytest.raises(PermissionError)),
61+
],
62+
)
63+
def test_user_project_group(config_project, pytest_error):
64+
"""Test _validate_environment for if current user's groups does not contain the project name."""
65+
app = Benchcab(benchcab_exe_path=None)
66+
with pytest_error:
67+
app._validate_environment(project=config_project, modules=[])

0 commit comments

Comments
 (0)