Contributing Guide

Introduction

The Case class is the core of the CIME Case Control system. All interactions with a case are performed through this class. The variables used to create and manipulate a case are defined in XML files, and for each XML file, there is a corresponding Python class to interact with it.

XML files that are part of the CIME distribution and are intended to be read-only with respect to a case are typically named config_something.xml. The corresponding Python class is named Something and can be found in the file CIME.XML.something.py. These are referred to as the CIME config classes.

XML files that are part of a case and thus are read/write to a case are typically named env_whatever.xml. The corresponding Python modules are CIME.XML.env_whatever.py, and the classes are named EnvWhatever. These are referred to as the Case env classes.

The Case class includes an array of the Case env classes. In the configure function and its supporting functions, the case object creates and manipulates the Case env classes by reading and interpreting the CIME config classes.

Testing

CIME splits its tests into two categories: unit and sys.

The unit category covers doctests and unit tests, while the sys category covers regression tests. Tests are named accordingly (e.g., unit tests: CIME/tests/test_unit*).

How to run the tests

There are two possible methods to run these tests.

Warning

scripts_regression_tests.py is deprecated and will be removed in the future.

pytest

CIME supports running tests using pytest. By using pytest coverage reports are automatically generated. pytest supports all the same arguments as scripts_regression_tests.py, see –help for details.

To get started install pytest and pytest-cov.

pip install -r test-requirements.txt
pip install pytest pytest-cov
Examples

Running all the sys and unit tests.

pytest

Running only sys tests, sys can be replaced with unit to run only unit testing.

pytest CIME/tests/test_sys.*

Running a specific test case.

pytest CIME/tests/test_unit_case.py

A specific test can be run with the following.

pytest CIME/tests/test_unit_case.py::TestCaseSubmit::test_check_case

scripts_regression_tests.py

The scripts_regression_tests.py script is located under CIME/tests.

You can pass either the module name or the file path of a test.

Examples

Running all the sys and unit tests.

python CIME/tests/scripts_regression_tests.py

Running only sys tests, sys can be replaced with unit to run only unit testing.

python CIME/tests/scripts_regression_tests.py CIME/tests/test_sys*

Runnig a specific test case.

python CIME/tests/scripts_regression_tests.py CIME.tests.test_unit_case

A specific test can be run with the following.

python CIME/tests/scripts_regression_tests.py CIME.tests.test_unit_case.TestCaseSubmit.test_check_case

Code Quality

To ensure code quality we require all code to be linted by pylint and formatted using black. We run a few other tools to check XML formatting, ending files with newlines and trailing white spaces.

To ensure consistency when running these checks we require the use of [pre-commit](https://pre-commit.com/).

Our GitHub actions will lint and check the format of each PR but will not automatically fix any issues. It’s up to the developer to resolve linting and formatting issues. We encourage installing pre-commit’s [Git hooks](#installing-git-hook-scripts) that will run these checks before code can be committed.

Installing pre-commit

pip install pre-commit

Running pre-commit

pre-commit run -a

Installing git hook scripts

If you install these scripts then pre-commit will automatically run on git commit.

pre-commit install

Docker container

CIME provides a container that the CI uses to run all the testing. This container

can also be used to test locally providing a reproducible environment. The

compiler is GNU and the MPI implementation is OpenMPI.

The image can be pulled from ghcr.io.

docker pull ghcr.io/esmci/cime:latest

or can be built locally. The build context needs to be set to the root of the CIME repository.

docker build -t ghcr.io/esmci/cime:latest -f docker/Dockerfile .

Running

The container does not provide any source, as such you will need to bind mount the model+cime directory and define which model is being used. The following example assumes the model is checked out in $SRC_PATH.

docker run -it --rm --hostname docker -e CIME_MODEL=e3sm -v ${SRC_PATH}:/root/model -v ./storage:/root/storage -v ./inputdata:/root/inputdata -w /root/E3SM/cime ghcr.io/esmci/cime:latest bash

This example will drop into a shell where CIME commands or tests can be run. The options are broken down below.

  • --hostname docker is required to tell CIME which machine definition to use.

  • -e CIME_MODEL=e3sm defines the model.

  • -v ${SRC_PATH}:/root/E3SM passes through the model source.

  • -v ./inputdata:/root/inputdata persistent input data.

  • -v ./storage:/root/storage persistent cases, baselines, timings, etc.

  • -w /root/E3SM/cime set the current working directory to CIME’s root.

  • ghcr.io/esmci/cime:latest container image.

  • bash the command to run in the container.

You can even run CIME or testing without a shell.

docker run -it --rm --hostname docker -e CIME_MODEL=e3sm -v ${SRC_PATH}:/root/model -v ./storage:/root/storage -w /root/E3SM/cime ghcr.io/esmci/cime:latest pytest CIME/tests/test_unit*
docker run -it --rm --hostname docker -e CIME_MODEL=e3sm -v ${SRC_PATH}:/root/model -v ./storage:/root/storage -w /root/E3SM/cime ghcr.io/esmci/cime:latest ./scripts/create_test SMS.f19_g16.S