Skip to content

Commit

Permalink
Update code to pass pre-commit lint/format checks
Browse files Browse the repository at this point in the history
  • Loading branch information
jo-basevi committed May 21, 2024
1 parent 403cc26 commit 8d0e291
Show file tree
Hide file tree
Showing 12 changed files with 321 additions and 307 deletions.
6 changes: 4 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ exclude = [
"site-packages",
"venv",
]

[tool.ruff.lint]
# E402: module level import not at top of file
# E501: line too long - let black worry about that
ignore = [
Expand All @@ -93,8 +95,8 @@ select = [
"UP",
]

[tool.ruff.mccabe]
[tool.ruff.lint.mccabe]
max-complexity = 18

[tool.ruff.isort]
[tool.ruff.lint.isort]
known-first-party = ["model_config_tests"]
1 change: 1 addition & 0 deletions src/model_config_tests/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

def main():
import pytest

errcode = pytest.main([HERE] + sys.argv[1:])
sys.exit(errcode)

Expand Down
58 changes: 32 additions & 26 deletions src/model_config_tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
# SPDX-License-Identifier: Apache-2.0

import os
import pytest
from pathlib import Path

import pytest
import yaml
from ruamel.yaml import YAML

Expand All @@ -14,19 +14,19 @@ def output_path(request):
"""Set the output path: This contains control and lab directories for each
test and test output files - e.g. CHECKSUMS
"""
path = request.config.getoption('--output-path')
path = request.config.getoption("--output-path")
if path is None:
# Set default to /scratch/PROJECT/USER/test-model-repro/
project = os.environ.get('PROJECT')
user = os.environ.get('USER')
path = f'/scratch/{project}/{user}/test-model-repro'
project = os.environ.get("PROJECT")
user = os.environ.get("USER")
path = f"/scratch/{project}/{user}/test-model-repro"
return Path(path)


@pytest.fixture(scope="session")
def control_path(request):
"""Set the path of the model configuration directory to test"""
path = request.config.getoption('--control-path')
path = request.config.getoption("--control-path")
if path is None:
# Set default to current working directory
path = Path.cwd()
Expand All @@ -36,17 +36,17 @@ def control_path(request):
@pytest.fixture(scope="session")
def checksum_path(request, control_path):
"""Set the path of the model configuration directory to test"""
path = request.config.getoption('--checksum-path')
path = request.config.getoption("--checksum-path")
if path is None:
# Set default to checksum stored on model configuration
path = control_path / 'testing' / 'checksum' / 'historical-3hr-checksum.json'
path = control_path / "testing" / "checksum" / "historical-3hr-checksum.json"
return Path(path)


@pytest.fixture(scope="session")
def metadata(control_path: Path):
"""Read the metadata file in the control directory"""
metadata_path = control_path / 'metadata.yaml'
metadata_path = control_path / "metadata.yaml"
# Use ruamel.yaml as that is what is used to read metadata files in Payu
# It also errors out if there are duplicate keys in metadata
content = YAML().load(metadata_path)
Expand All @@ -56,7 +56,7 @@ def metadata(control_path: Path):
@pytest.fixture(scope="session")
def config(control_path: Path):
"""Read the config file in the control directory"""
config_path = control_path / 'config.yaml'
config_path = control_path / "config.yaml"
with open(config_path) as f:
config_content = yaml.safe_load(f)
return config_content
Expand All @@ -67,27 +67,33 @@ def target_branch(request):
"""Set the target branch - i.e., the branch the configuration will be
merged into. This used is to infer configuration information, if the
configuration branches follow a common naming scheme (e.g. ACCESS-OM2)"""
return request.config.getoption('--target-branch')
return request.config.getoption("--target-branch")


# Set up command line options and default for directory paths
def pytest_addoption(parser):
"""Attaches optional command line arguments"""
parser.addoption("--output-path",
action="store",
help="Specify the output directory path for test output")

parser.addoption("--control-path",
action="store",
help="Specify the model configuration path to test")

parser.addoption("--checksum-path",
action="store",
help="Specify the checksum file to compare against")

parser.addoption("--target-branch",
action="store",
help="Specify the target branch name")
parser.addoption(
"--output-path",
action="store",
help="Specify the output directory path for test output",
)

parser.addoption(
"--control-path",
action="store",
help="Specify the model configuration path to test",
)

parser.addoption(
"--checksum-path",
action="store",
help="Specify the checksum file to compare against",
)

parser.addoption(
"--target-branch", action="store", help="Specify the target branch name"
)


def pytest_configure(config):
Expand Down
84 changes: 42 additions & 42 deletions src/model_config_tests/exp_test_helper.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
# Copyright 2024 ACCESS-NRI and contributors. See the top-level COPYRIGHT file for details.
# SPDX-License-Identifier: Apache-2.0

import subprocess as sp
import shutil
import re
import glob
import os
import re
import shutil
import subprocess as sp
import sys
import glob
import yaml
from pathlib import Path

from model_config_tests.util import wait_for_qsub
import yaml

from model_config_tests.models import index as model_index
from model_config_tests.util import wait_for_qsub


class ExpTestHelper(object):
class ExpTestHelper:

def __init__(self, control_path: Path, lab_path: Path):

self.exp_name = control_path.name
self.control_path = control_path
self.lab_path = lab_path
self.config_path = control_path / 'config.yaml'
self.archive_path = lab_path / 'archive' / self.exp_name
self.work_path = lab_path / 'work' / self.exp_name
self.output000 = self.archive_path / 'output000'
self.output001 = self.archive_path / 'output001'
self.config_path = control_path / "config.yaml"
self.archive_path = lab_path / "archive" / self.exp_name
self.work_path = lab_path / "work" / self.exp_name
self.output000 = self.archive_path / "output000"
self.output001 = self.archive_path / "output001"

with open(self.config_path) as f:
self.config = yaml.safe_load(f)
Expand All @@ -35,13 +36,13 @@ def __init__(self, control_path: Path, lab_path: Path):
def set_model(self):
"""Set model based on payu config. Currently only setting top-level
model"""
self.model_name = self.config.get('model')
self.model_name = self.config.get("model")
ModelType = model_index[self.model_name]
self.model = ModelType(self)

def extract_checksums(self,
output_directory: Path = None,
schema_version: str = None):
def extract_checksums(
self, output_directory: Path = None, schema_version: str = None
):
"""Use model subclass to extract checksums from output"""
return self.model.extract_checksums(output_directory, schema_version)

Expand All @@ -61,17 +62,17 @@ def setup_for_test_run(self):
doc = yaml.safe_load(f)

# Disable git runlog
doc['runlog'] = False
doc["runlog"] = False

# Disable metadata and set override experiment name for work/archive
# directories
doc['metadata'] = {"enable": False}
doc['experiment'] = self.exp_name
doc["metadata"] = {"enable": False}
doc["experiment"] = self.exp_name

# Set laboratory path
doc['laboratory'] = str(self.lab_path)
doc["laboratory"] = str(self.lab_path)

with open(self.config_path, 'w') as f:
with open(self.config_path, "w") as f:
yaml.dump(doc, f)

def run(self):
Expand All @@ -95,56 +96,56 @@ def force_qsub_run(self):
owd = Path.cwd()
try:
os.chdir(self.control_path)
sp.check_output(['payu', 'sweep', '--lab', self.lab_path])
run_id = sp.check_output(['payu', 'run', '--lab', self.lab_path])
sp.check_output(["payu", "sweep", "--lab", self.lab_path])
run_id = sp.check_output(["payu", "run", "--lab", self.lab_path])
run_id = run_id.decode().splitlines()[0]
except sp.CalledProcessError as err:
print('Error: call to payu run failed.', file=sys.stderr)
except sp.CalledProcessError:
print("Error: call to payu run failed.", file=sys.stderr)
return 1, None, None, None
finally:
os.chdir(owd)

wait_for_qsub(run_id)
run_id = run_id.split('.')[0]
run_id = run_id.split(".")[0]

output_files = []
# Read qsub stdout file
stdout_filename = glob.glob(str(self.control_path / f'*.o{run_id}'))
stdout_filename = glob.glob(str(self.control_path / f"*.o{run_id}"))
print(stdout_filename)
if len(stdout_filename) != 1:
print('Error: there are too many stdout files.', file=sys.stderr)
print("Error: there are too many stdout files.", file=sys.stderr)
return 2, None, None, None

stdout_filename = stdout_filename[0]
output_files.append(stdout_filename)
stdout = ''
with open(stdout_filename, 'r') as f:
stdout = ""
with open(stdout_filename) as f:
stdout = f.read()

# Read qsub stderr file
stderr_filename = glob.glob(str(self.control_path / f'*.e{run_id}'))
stderr = ''
stderr_filename = glob.glob(str(self.control_path / f"*.e{run_id}"))
stderr = ""
if len(stderr_filename) == 1:
stderr_filename = stderr_filename[0]
output_files.append(stderr_filename)
with open(stderr_filename, 'r') as f:
with open(stderr_filename) as f:
stderr = f.read()

# TODO: Early return if not collating

# Read the qsub id of the collate job from the stdout.
# Payu puts this here.
m = re.search(r'(\d+.gadi-pbs)\n', stdout)
m = re.search(r"(\d+.gadi-pbs)\n", stdout)
if m is None:
print('Error: qsub id of collate job.', file=sys.stderr)
print("Error: qsub id of collate job.", file=sys.stderr)
return 3, stdout, stderr, output_files

# Wait for the collate to complete.
run_id = m.group(1)
wait_for_qsub(run_id)

# Return files created by qsub so caller can read or delete.
collate_files = self.control_path / f'*.[oe]{run_id}'
collate_files = self.control_path / f"*.[oe]{run_id}"
output_files += glob.glob(str(collate_files))

return 0, stdout, stderr, output_files
Expand All @@ -159,20 +160,19 @@ def setup_exp(control_path: Path, output_path: Path, exp_name: str):
Create a exp by copying over base config
"""
# Set experiment control path
if control_path.name != 'base-experiment':
exp_name = f'{control_path.name}-{exp_name}'
if control_path.name != "base-experiment":
exp_name = f"{control_path.name}-{exp_name}"

exp_control_path = output_path / 'control' / exp_name
exp_control_path = output_path / "control" / exp_name

# Copy over base control directory (e.g. model configuration)
if exp_control_path.exists():
shutil.rmtree(exp_control_path)
shutil.copytree(control_path, exp_control_path, symlinks=True)

exp_lab_path = output_path / 'lab'
exp_lab_path = output_path / "lab"

exp = ExpTestHelper(control_path=exp_control_path,
lab_path=exp_lab_path)
exp = ExpTestHelper(control_path=exp_control_path, lab_path=exp_lab_path)

# Remove any pre-existing archive or work directories for the experiment
try:
Expand Down
4 changes: 1 addition & 3 deletions src/model_config_tests/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from model_config_tests.models.accessom2 import AccessOm2

index = {
'access-om2': AccessOm2
}
index = {"access-om2": AccessOm2}
Loading

0 comments on commit 8d0e291

Please sign in to comment.