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

Warning

The legacy scripts_regression_tests.py entry point has been replaced by pytest.

CIME supports running tests using pytest. By using pytest coverage reports are automatically generated. Install the test requirements, which include pytest and pytest-cov:

pip install -r test-requirements.txt

Common examples

Run all sys and unit tests.

pytest

Run only sys tests. Replace sys with unit to run only unit tests.

pytest CIME/tests/test_sys*

Run a specific test case.

pytest CIME/tests/test_unit_case.py

Run a specific test method.

pytest CIME/tests/test_unit_case.py::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 [pre-commit](https://pre-commit.com/).

GitHub Actions lint and check the format of each PR, but they do not automatically fix issues. Installing the pre-commit [Git hooks](#installing-git-hook-scripts) runs those checks before each commit.

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 CI uses to run tests. You can also use it locally for a reproducible environment. The compiler is GNU and the MPI implementation is OpenMPI.

The image can be pulled from ghcr.io or built locally. For local builds, set the build context to the root of the CIME repository.

docker pull ghcr.io/esmci/cime:latest

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

Running

The container does not include source code, so bind mount the model checkout and choose the model 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 -w /root/model/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/model passes through the model source.

  • -v ./storage:/root/storage persists data such as cases, baselines, archive, and inputdata. Files are created with world-readable permissions so they can be accessed from the host in real-time.

  • -w /root/model/cime sets 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 also run CIME commands or tests without opening a shell.

docker run -it --rm --hostname docker -e CIME_MODEL=e3sm -v ${SRC_PATH}:/root/model -v ./storage:/root/storage -w /root/model/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/model/cime ghcr.io/esmci/cime:latest ./scripts/create_test SMS.f19_g16.S

Using Podman

Podman can be used as a drop-in replacement for Docker. Use podman unshare to run commands within Podman’s user namespace, allowing access to files created in bind mounts.

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

Run tests directly:

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

To access files in ./storage from the host while the container is running, use podman unshare:

podman unshare ls -la ./storage