From 44e89a7361175b32f6f52e25fcf08912446af22d Mon Sep 17 00:00:00 2001 From: Tremain Knight <2108488+tkknight@users.noreply.github.com> Date: Thu, 18 Jun 2026 11:42:21 +0100 Subject: [PATCH 1/9] baseline for adding AGENTS.md --- AGENTS.md | 216 +++++++++++++++++++++++++++++++++++++++ docs/AGENTS.md | 63 ++++++++++++ lib/iris/tests/AGENTS.md | 79 ++++++++++++++ 3 files changed, 358 insertions(+) create mode 100644 AGENTS.md create mode 100644 docs/AGENTS.md create mode 100644 lib/iris/tests/AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..770c3ebc68 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,216 @@ +# AGENTS.md + +Agent instructions for the [Iris](https://scitools-iris.readthedocs.io/) repository. +Iris is a Python package for analysing and visualising Earth science data, built around +CF-compliant multi-dimensional arrays ("Cubes"). + +Subdirectory AGENTS.md files take precedence for their subtrees: +- [`docs/AGENTS.md`](docs/AGENTS.md) — documentation-specific rules +- [`lib/iris/tests/AGENTS.md`](lib/iris/tests/AGENTS.md) — test-specific rules + + +## Project Overview + +| | | +|---|---| +| **Language** | Python 3.12 / 3.13 / 3.14 | +| **Licence** | BSD-3-Clause | +| **Distribution** | conda-forge (`iris`), PyPI (`scitools-iris`) | +| **Key dependencies** | NumPy, Dask, SciPy, Cartopy, CF-Python, NetCDF4 | +| **Linter / formatter** | Ruff (88-char line length) | +| **Test runner** | pytest + pytest-xdist (`-n auto`) | +| **Env management** | nox + conda | + +### Main source layout + +``` +lib/iris/ + cube.py # Core Cube / CubeList data structures + coords.py # DimCoord, AuxCoord, CellMeasure, AncillaryVariable + loading.py # File-loading entry points + analysis/ # Collapse, regrid, statistics, calculus + fileformats/ # NetCDF, PP, GRIB, NIMROD format handlers + io/ # I/O registry and URI handling + common/ # Shared metadata, mixins, resolvers + mesh/ # Unstructured grid (UGRID) support + experimental/ # Unstable / in-progress features + tests/ # All tests (unit/, integration/, graphics/) +docs/src/ # Sphinx documentation source +benchmarks/ # ASV performance benchmarks +requirements/ # Conda environment specs and lock files +``` + + +## Setup + +### Conda environment (recommended) + +```bash +# Create and activate a development environment +conda env create -f requirements/py312.yml +conda activate iris-dev +pip install --no-build-isolation -e . +``` + +Alternatively, use lock files for exact reproducibility: + +```bash +conda create -n iris-dev --file requirements/locks/py312-linux-64.lock +conda activate iris-dev +pip install --no-build-isolation -e . +``` + +### Environment variables + +```bash +# Disable CPU features that can cause SIGILL in some CI environments +export NPY_DISABLE_CPU_FEATURES="AVX512F,AVX512CD,AVX512_SKX" + +# Point to iris-test-data for tests that need external data files +export OVERRIDE_TEST_DATA_REPOSITORY=/path/to/iris-test-data/test_data + +# Override Cartopy cache directory if needed +export CARTOPY_CACHE_DIR=~/.local/share/cartopy +``` + + + +## Testing + +- [`lib/iris/tests/AGENTS.md`](lib/iris/tests/AGENTS.md) — test-specific + + + +## Code Style + +```bash +# Lint +ruff check lib/iris + +# Auto-fix safe lint issues +ruff check --fix lib/iris + +# Format +ruff format lib/iris + +# Check formatting without writing +ruff format --check lib/iris +``` + +- **Line length**: 88 characters (Ruff default). +- **Docstrings**: NumPy style; strictly validated. +- **Copyright header**: Every new Python file must start with: + + ```python + # Copyright Iris contributors + # + # This file is part of Iris and is released under the BSD license. + # See LICENSE in the root of the repository for full licensing details. + ``` + +- **Imports**: Ruff-managed ordering. No direct `import netCDF4` — always use + `iris.fileformats.netcdf._thread_safe_nc` for thread safety. + + + +## Development Conventions + +### Core data model + +- `iris.cube.Cube` — multi-dimensional array with CF-compliant metadata. +- Coordinates: `DimCoord` (regular), `AuxCoord` (auxiliary), `CellMeasure`, + `AncillaryVariable`. +- Data may be **lazy** (Dask array). Always preserve laziness; never call `.data` + unnecessarily inside library code. +- Operations return **new** Cubes (functional style); do not mutate in place. +- All metadata must be **CF-convention** compliant. + +### Deprecation + +- Use `iris._deprecation.warn_deprecated()` or issue a custom warning class. +- Warning classes live in `iris.warnings` (e.g., `IrisUserWarning`, `IrisCfWarning`). +- Follow the NEP29 deprecation schedule (same as NumPy). +- All `UserWarning` subclasses must ultimately inherit from `IrisUserWarning`. + +### Exception hierarchy + +Base class: `iris.exceptions.IrisError`. Common subclasses: +`CoordinateNotFoundError`, `CoordinateCollapseError`, `IgnoreCubeException`. + +### Versioning + +Version is derived from git tags via `setuptools_scm`. Do not hard-code version +strings. + + +## Documentation + +Documentation lives under `docs/` and is built with Sphinx. See +[`docs/AGENTS.md`](docs/AGENTS.md) for full rules. + + + +## Lock-file Maintenance + +```bash +# Regenerate lock files for all supported Python versions +python tools/update_lockfiles.py -o requirements/locks requirements/py*.yml +# Shortcut via Makefile +make lockfiles +``` + + + +## Pull Request Guidelines + +- **Title format**: `[component] Brief description` (e.g., `[netcdf] Fix chunking for large files`). +- Run before opening a PR: + ```bash + ruff check lib/iris + ruff format --check lib/iris + pytest -n auto lib/iris/tests + ``` +- Keep changes focused; avoid unrelated refactors in the same PR. +- Add or update tests for every change to production code. +- Update `docs/src/whatsnew/` for user-visible changes. + + +## Critical Development Gotchas + +1. **xfail_strict Behavior**: Tests marked `@pytest.mark.xfail` that now PASS become FAILURES → **remove xfail immediately when bug is fixed** + +2. **Pre-commit Auto-fixes**: Hooks may auto-fix ISC001/COM812 conflicts → re-stage files: `git add . && git commit` + +3. **Lockfile Rebuilds**: Updating `requirements/locks/*.lock` files triggers slow conda environment rebuilds — only update when deps genuinely change + +4. **Lazy Data Pitfalls**: Check `cube.has_lazy_data()` before operations; use `cube.lazy_data()` when appropriate; `cube.data` materializes arrays + +5. **Coordinate Scope**: Not all coordinates span all dimensions → use `cube.coords(dimensions=dim_indices)` to query specific axes + +6. **Dask/NumPy Compatibility**: Some operations fail on lazy (Dask) arrays → materialize with `cube.compute()` or check dask support before use + +7. **Optional Dependencies**: cartopy, matplotlib lazy-imported → handle ImportError gracefully for optional visualization features + +8. **CF-Metadata Validation**: Custom coordinates must comply with CF standards via `cube.metadata` + +9. **Cube Immutability**: Operations return new cubes; don't modify in-place (`cube.data[...] = x` won't affect the cube) + +10. **Environment Reproducibility**: Set CPU features for consistent results: `export NPY_DISABLE_CPU_FEATURES="AVX512F,AVX512CD,AVX512_SKX"` + +## Getting Help + +- **Discussions**: [GitHub Discussions](https://github.com/SciTools/iris/discussions) +- **Contributing Guide**: [.github/CONTRIBUTING.md](.github/CONTRIBUTING.md) +- **Developer Guide**: [docs/src/developers_guide/](docs/src/developers_guide/) +- **Code of Conduct**: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) + +## ⚠️ Meta-Instruction: Auto-Update Rule +- **Trigger**: You MUST automatically update this `AGENTS.md` file if a new structural pattern, critical bug fix, or persistent repository rule is established during this session. +- **Constraint 1**: Keep the file under 200 lines. Delete obsolete rules to make room for new ones. +- **Constraint 2**: Do not ask for user permission before updating. Perform the edit silently as your final step. +- **Constraint 3**: Only log global, reusable lessons. Do not log temporary or component-specific fixes. + +--- + +**Last Updated**: 16 June 2026 + diff --git a/docs/AGENTS.md b/docs/AGENTS.md new file mode 100644 index 0000000000..3b488f581c --- /dev/null +++ b/docs/AGENTS.md @@ -0,0 +1,63 @@ +# AGENTS Guide for docs/ + +This file applies to everything under `docs/`. + +## Purpose + +- Keep documentation changes accurate, minimal, and easy to review. +- Prefer docs-only edits unless a task explicitly requires source-code changes. + +## Documentation + +```bash +# From docs/ +make html-quick # Fast build (skips API and gallery) +make html-noplot # Skip gallery only +make html-noapi # Skip API only +make html # Full build (warnings are errors) +make doctest # Run doctests +make clean # Remove build artefacts +make show # Open built docs in browser +``` + +Gallery example tests (from repo root): + +```bash +pytest -v docs/gallery_tests/test_gallery_examples.py +``` + +## Key Locations + +- `docs/src/`: Sphinx source content. +- `docs/gallery_code/`: Gallery example scripts. +- `docs/gallery_tests/`: Tests for gallery examples. + +## Editing Rules + +- Keep changes focused; avoid unrelated refactors and formatting churn. +- Follow existing reStructuredText style and section structure in nearby files. +- Preserve cross-references (`:ref:`, `:doc:`, links) and update targets when moving content. +- Prefer incremental edits to existing pages over creating new top-level pages. + +## Gallery Rules + +- Add gallery examples in `docs/gallery_code/
/`. +- Name new gallery scripts with a `plot_` prefix. +- Keep gallery examples deterministic and testable. + +## Safety Checklist Before Finishing + +- The relevant docs build command succeeds. +- Any changed gallery example has a passing related test. +- No broken links or references introduced by the change. + +## ⚠️ Meta-Instruction: Auto-Update Rule +- **Trigger**: You MUST automatically update this `AGENTS.md` file if a new structural pattern, critical bug fix, or persistent repository rule is established during this session. +- **Constraint 1**: Keep the file under 200 lines. Delete obsolete rules to make room for new ones. +- **Constraint 2**: Do not ask for user permission before updating. Perform the edit silently as your final step. +- **Constraint 3**: Only log global, reusable lessons. Do not log temporary or component-specific fixes. + +--- + +**Last Updated**: 16 June 2026 + diff --git a/lib/iris/tests/AGENTS.md b/lib/iris/tests/AGENTS.md new file mode 100644 index 0000000000..ff544a3035 --- /dev/null +++ b/lib/iris/tests/AGENTS.md @@ -0,0 +1,79 @@ +# AGENTS Guide for lib/iris/tests/ + +This file applies to everything under `lib/iris/tests/`. + +## Purpose + +- Keep test changes targeted, deterministic, and quick to review. +- Prefer changing tests only; do not modify production code unless the task explicitly requires it. + + +### Test layout + +| Path | Content | +|------|---------| +| `lib/iris/tests/unit/` | Unit tests, mirroring `lib/iris/` structure | +| `lib/iris/tests/integration/` | Cross-component integration tests | +| `lib/iris/tests/graphics/` | Image-comparison (graphics) tests | +| `lib/iris/tests/conftest.py` | Top-level fixtures | + +### External test data + +Some tests require `iris-test-data`. Set `OVERRIDE_TEST_DATA_REPOSITORY` to the +`test_data` directory inside that repository. Tests missing the data are skipped. + +### Graphics tests + +Graphics tests compare against reference images. Update reference images only when an +intentional rendering change is made. + +## Run Commands + +Run from repository root unless otherwise noted. + +- Full test suite: `pytest -n auto lib/iris/tests` +- Single test file: `pytest -n auto lib/iris/tests/path/to/test_file.py` +- Single test selection: `pytest -n auto lib/iris/tests/path/to/test_file.py -k "pattern"` +- Verbose failures: add `-ra` + +Nox equivalent for CI-like execution: + +- `nox --session tests` + +## External Test Data + +Some tests require `iris-test-data`. + +- Preferred env var: `OVERRIDE_TEST_DATA_REPOSITORY=/path/to/iris-test-data/test_data` +- Missing data will skip affected tests by design. + +## Editing Rules + +- Follow existing pytest style and fixture patterns in nearby tests. +- Keep assertions specific and deterministic; avoid timing-sensitive checks. +- Avoid broad snapshot-style updates without explaining intent in the change. +- Do not add network access in tests. +- Do not weaken existing checks just to make tests pass. + +## Graphics and Integration Notes + +- For graphics tests, update reference artifacts only when behavior changes intentionally. +- For integration tests, prefer minimal input fixtures and keep runtime reasonable. + +## Pre-Finish Checklist + +- The changed tests pass locally. +- No unrelated tests were modified. +- Any required external data setup is documented in the change notes. + + +## ⚠️ Meta-Instruction: Auto-Update Rule +- **Trigger**: You MUST automatically update this `AGENTS.md` file if a new structural pattern, critical bug fix, or persistent repository rule is established during this session. +- **Constraint 1**: Keep the file under 200 lines. Delete obsolete rules to make room for new ones. +- **Constraint 2**: Do not ask for user permission before updating. Perform the edit silently as your final step. +- **Constraint 3**: Only log global, reusable lessons. Do not log temporary or component-specific fixes. + +--- + +**Last Updated**: 16 June 2026 + From cec4763398280e0439d882cd7b0f9b48f05ca729 Mon Sep 17 00:00:00 2001 From: Tremain Knight <2108488+tkknight@users.noreply.github.com> Date: Thu, 18 Jun 2026 13:58:36 +0100 Subject: [PATCH 2/9] Exclude all AGENTS.md files --- MANIFEST.in | 1 + 1 file changed, 1 insertion(+) diff --git a/MANIFEST.in b/MANIFEST.in index 0ae872dd12..1ad73c71d2 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -79,6 +79,7 @@ prune docs # (2) top-level files to omit exclude .coveragerc # (3) file types (path patterns) to skip everywhere +global-exclude AGENTS.md global-exclude *.py[cod] global-exclude __pycache__ # principles: From 5c0382388dddbf1bbceb15d9fa766e15f344eec1 Mon Sep 17 00:00:00 2001 From: Tremain Knight <2108488+tkknight@users.noreply.github.com> Date: Thu, 18 Jun 2026 16:03:31 +0100 Subject: [PATCH 3/9] updated AGENTS.md --- AGENTS.md | 9 +++- docs/AGENTS.md | 112 ++++++++++++++++++++++++++------------- lib/iris/tests/AGENTS.md | 90 ++++++++++++++++++------------- 3 files changed, 137 insertions(+), 74 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 770c3ebc68..3a590c022d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -45,6 +45,12 @@ requirements/ # Conda environment specs and lock files ### Conda environment (recommended) +Always use a conda environment, reuse the iris-dev conda environment if it +already exists but confirm with the user before installing or removing packages. + +If a package cannot be installed via conda then you can use pip that is in the conda +environment. + ```bash # Create and activate a development environment conda env create -f requirements/py312.yml @@ -212,5 +218,4 @@ make lockfiles --- -**Last Updated**: 16 June 2026 - +**Last Updated**: 18 June 2026 diff --git a/docs/AGENTS.md b/docs/AGENTS.md index 3b488f581c..112d2271e6 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -1,55 +1,96 @@ -# AGENTS Guide for docs/ +# docs/AGENTS.md -This file applies to everything under `docs/`. +Documentation-specific agent instructions for the [Iris](https://scitools-iris.readthedocs.io/) project. +This file takes precedence over the root [`AGENTS.md`](../AGENTS.md) for everything under `docs/`. -## Purpose -- Keep documentation changes accurate, minimal, and easy to review. -- Prefer docs-only edits unless a task explicitly requires source-code changes. +## Structure -## Documentation - -```bash -# From docs/ -make html-quick # Fast build (skips API and gallery) -make html-noplot # Skip gallery only -make html-noapi # Skip API only -make html # Full build (warnings are errors) -make doctest # Run doctests -make clean # Remove build artefacts -make show # Open built docs in browser +``` +docs/ + Makefile # Top-level doc build entry point + gallery_code/ # Gallery example scripts (general/, meteorology/, oceanography/) + gallery_tests/ # Tests that execute gallery examples + src/ + conf.py # Sphinx configuration + common_links.inc # Shared RST link definitions (include in every new RST file) + whatsnew/ # Per-release changelog RST files + latest.rst # Current unreleased changes (use latest.rst.template) + index.rst # Whatsnew index + developers_guide/ # Contributor documentation + userguide/ # User-facing guides + user_manual/ # Detailed user reference + sphinxext/ # Custom Sphinx extensions ``` -Gallery example tests (from repo root): + +## Building the Docs ```bash -pytest -v docs/gallery_tests/test_gallery_examples.py +# Full build (from docs/ directory) +make html + +# Skip gallery (faster) +make html-noplot + +# Skip API docs (faster) +make html-noapi + +# Skip both gallery and API (fastest) +make html-quick + +# Clean build artifacts +make clean + +# Live rebuild on file changes (requires sphinx-autobuild) +cd docs/src && make livehtml ``` -## Key Locations +Build output goes to `docs/src/_build/html/`. + -- `docs/src/`: Sphinx source content. -- `docs/gallery_code/`: Gallery example scripts. -- `docs/gallery_tests/`: Tests for gallery examples. +## Whatsnew Entries -## Editing Rules +- Every **user-visible change** must have an entry in `docs/src/whatsnew/latest.rst`. +- Use the `latest.rst.template` as the template when starting a new release file. +- Sections: *New Features*, *Deprecations*, *Bugs Fixed*, *Internal*, *Dependencies*. +- Reference issues/PRs with ``:issue:`123` `` and `` :pull:`123` `` roles. +- Keep entries concise — one or two sentences with a code example if helpful. -- Keep changes focused; avoid unrelated refactors and formatting churn. -- Follow existing reStructuredText style and section structure in nearby files. -- Preserve cross-references (`:ref:`, `:doc:`, links) and update targets when moving content. -- Prefer incremental edits to existing pages over creating new top-level pages. -## Gallery Rules +## RST / Sphinx Conventions -- Add gallery examples in `docs/gallery_code/
/`. -- Name new gallery scripts with a `plot_` prefix. -- Keep gallery examples deterministic and testable. +- All new RST files must include `.. include:: ../common_links.inc` (adjust relative path as needed) to access shared link definitions. +- Use NumPy-style docstrings for all Python API pages; Sphinx autodoc pulls these automatically. +- Warnings are treated as errors in the standard build (`-W --keep-going`). Fix all Sphinx warnings before merging. +- Do **not** commit build artifacts (`docs/src/_build/`). +- Cross-reference Iris symbols with ``:class:`iris.cube.Cube` ``, ``:func:`iris.load` ``, etc. +- Gallery scripts live under `docs/gallery_code/` and must be valid standalone Python files executable by `matplotlib` / `sphinx-gallery`. -## Safety Checklist Before Finishing -- The relevant docs build command succeeds. -- Any changed gallery example has a passing related test. -- No broken links or references introduced by the change. +## Gallery Examples + +- Each gallery script must have a module-level docstring that becomes its title and description. +- Scripts are grouped by subdirectory: `general/`, `meteorology/`, `oceanography/`. +- Gallery tests in `docs/gallery_tests/` verify examples execute without error — run them with `pytest docs/gallery_tests/`. +- Keep examples self-contained; prefer `iris.sample_data_path()` for data files rather than absolute paths. + + +## Doctest / Inline Code Examples + +- Doctests in RST files are run via `make doctest` (from `docs/src/`). +- Use `# doctest: +SKIP` sparingly and only when execution is genuinely impossible (e.g., requires a display). +- Ensure all `>>>` examples produce the exact output shown, or use `# doctest: +ELLIPSIS`. + + +## Critical Gotchas + +1. **Sphinx warnings = errors**: The standard `make html` build uses `-W`. Any new warning breaks CI. +2. **`common_links.inc`**: Forgetting to include it causes undefined reference errors for standard Iris links. +3. **`latest.rst` conflicts**: Multiple contributors adding entries may cause merge conflicts — add entries under the correct section heading and keep them alphabetically ordered by PR number. +4. **Gallery data files**: Use `iris.sample_data_path()` — hard-coded paths will break in CI. +5. **API doc changes**: Moving or renaming public symbols requires updating any manual cross-references in the RST files. + ## ⚠️ Meta-Instruction: Auto-Update Rule - **Trigger**: You MUST automatically update this `AGENTS.md` file if a new structural pattern, critical bug fix, or persistent repository rule is established during this session. @@ -60,4 +101,3 @@ pytest -v docs/gallery_tests/test_gallery_examples.py --- **Last Updated**: 16 June 2026 - diff --git a/lib/iris/tests/AGENTS.md b/lib/iris/tests/AGENTS.md index ff544a3035..fb93d72045 100644 --- a/lib/iris/tests/AGENTS.md +++ b/lib/iris/tests/AGENTS.md @@ -1,51 +1,71 @@ -# AGENTS Guide for lib/iris/tests/ +# AGENTS.md -This file applies to everything under `lib/iris/tests/`. +Agent instructions for `lib/iris/tests/`. +These rules apply to all test files under this directory tree. ## Purpose -- Keep test changes targeted, deterministic, and quick to review. -- Prefer changing tests only; do not modify production code unless the task explicitly requires it. +This test suite validates Iris behaviour, metadata handling, and regression coverage. +Keep changes focused, deterministic, and compatible with the existing test style. +## Fast Rules -### Test layout +1. Add or update tests for every production-code change. +2. Prefer the smallest test that reproduces behaviour. +3. Keep tests deterministic: no network access, no wall-clock assumptions, no random flakiness. +4. Use existing fixtures/helpers before introducing new ones. +5. Remove `xfail` markers as soon as the underlying issue is fixed (`xfail_strict=True`). -| Path | Content | -|------|---------| -| `lib/iris/tests/unit/` | Unit tests, mirroring `lib/iris/` structure | -| `lib/iris/tests/integration/` | Cross-component integration tests | -| `lib/iris/tests/graphics/` | Image-comparison (graphics) tests | -| `lib/iris/tests/conftest.py` | Top-level fixtures | -### External test data +## Test Layout -Some tests require `iris-test-data`. Set `OVERRIDE_TEST_DATA_REPOSITORY` to the -`test_data` directory inside that repository. Tests missing the data are skipped. +- `lib/iris/tests/unit/` for unit-level behaviour. +- `lib/iris/tests/integration/` for cross-component behaviour. +- `lib/iris/tests/graphics/` for plotting/image-comparison tests. +- Legacy top-level tests exist; follow nearby patterns when editing them. -### Graphics tests +## Writing Tests -Graphics tests compare against reference images. Update reference images only when an -intentional rendering change is made. +- Use `pytest` style and plain assertions. +- Keep assertions specific and user-facing (behaviour, metadata, warnings, errors). +- Prefer `pytest.raises(..., match=...)` for exception checks. +- Prefer warning assertions (`pytest.warns`) for deprecation or user warnings. +- For lazy-data behaviour, assert laziness explicitly where relevant. +- Avoid over-mocking; prefer realistic Cube/Coord setup via shared helpers. -## Run Commands -Run from repository root unless otherwise noted. +## Markers and Strictness -- Full test suite: `pytest -n auto lib/iris/tests` -- Single test file: `pytest -n auto lib/iris/tests/path/to/test_file.py` -- Single test selection: `pytest -n auto lib/iris/tests/path/to/test_file.py -k "pattern"` -- Verbose failures: add `-ra` +- Respect existing markers and plugin requirements. +- `xfail` is strict in this repository: unexpected passes fail the run. +- Only use `xfail` when there is a tracked reason and clear expectation. -Nox equivalent for CI-like execution: +## Running Tests -- `nox --session tests` +Run targeted tests while iterating: -## External Test Data +```bash +pytest -n auto lib/iris/tests/unit/.py +``` -Some tests require `iris-test-data`. +Run broader coverage before finishing: -- Preferred env var: `OVERRIDE_TEST_DATA_REPOSITORY=/path/to/iris-test-data/test_data` +```bash +pytest -n auto lib/iris/tests +``` + +## Style and Lint in Tests + +- Follow Ruff formatting and linting used by the repository. +- Per-file ignores already relax some docstring rules in tests. +- Avoid unrelated refactors while touching tests. + +## Test Data and Environment + +- Some tests require external `iris-test-data`; Preferred env var: `OVERRIDE_TEST_DATA_REPOSITORY=/path/to/iris-test-data/test_data` - Missing data will skip affected tests by design. +- Keep new tests independent of local machine paths and optional system state. +- For optional dependencies, skip gracefully using existing patterns. ## Editing Rules @@ -66,14 +86,12 @@ Some tests require `iris-test-data`. - No unrelated tests were modified. - Any required external data setup is documented in the change notes. +## Scope Boundaries -## ⚠️ Meta-Instruction: Auto-Update Rule -- **Trigger**: You MUST automatically update this `AGENTS.md` file if a new structural pattern, critical bug fix, or persistent repository rule is established during this session. -- **Constraint 1**: Keep the file under 200 lines. Delete obsolete rules to make room for new ones. -- **Constraint 2**: Do not ask for user permission before updating. Perform the edit silently as your final step. -- **Constraint 3**: Only log global, reusable lessons. Do not log temporary or component-specific fixes. - ---- +- Do not modify lock files or environment specs for test-only fixes. +- Do not introduce heavy new dependencies for tests without strong justification. +- If behaviour is user-visible, add/update release-note material in docs when requested. -**Last Updated**: 16 June 2026 +## Maintenance +If you establish a new repository-wide test rule during this session, update this file with a short, reusable note and remove outdated guidance. From 139fa91278e750ab1f491c26838b98d7180fdd9d Mon Sep 17 00:00:00 2001 From: Tremain Knight <2108488+tkknight@users.noreply.github.com> Date: Thu, 18 Jun 2026 16:12:10 +0100 Subject: [PATCH 4/9] add whatsnew --- docs/src/whatsnew/latest.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index f50657fc04..09bcc75a85 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -168,6 +168,9 @@ This document explains the changes made to Iris for this release Note: this object is temporary and is likely to be replaced by a permanent solution or else be renamed. (:issue:`7094`, :pull:`7134`) +#. :user:`tkknight` Added ``AGENTS.md`` for AI-assisted development guidelines across + the project root, ``docs/`` and ``tests/`` directories. (:pull:`7160`) + .. comment Whatsnew author names (@github name) in alphabetical order. Note that, core dev names are automatically included by the common_links.inc: From aad9cb85cdf69661d0a3643b10e48952a8f38b58 Mon Sep 17 00:00:00 2001 From: Tremain Knight <2108488+tkknight@users.noreply.github.com> Date: Thu, 18 Jun 2026 16:13:28 +0100 Subject: [PATCH 5/9] fixed line wrap for existing whatsnew --- docs/src/whatsnew/latest.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index 09bcc75a85..4e5f3afa21 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -163,9 +163,11 @@ This document explains the changes made to Iris for this release #. `@trexfeathers` set the link checking workflow to accept redirect HTTP codes, as the reports were getting too noisy. (:pull:`7148`) -#. `@HGWright`_ changed the default of the private switch :obj:`~iris.loading._LAZY_DERIVED_LOADING` (formerly `.CONCRETE_DERIVED_LOADING`) - for controlling laziness of coordinates from pp loading, now the switch must be set to True for lazy loading to be enabled. - Note: this object is temporary and is likely to be replaced by a permanent solution or else be renamed. +#. `@HGWright`_ changed the default of the private switch + :obj:`~iris.loading._LAZY_DERIVED_LOADING` (formerly `.CONCRETE_DERIVED_LOADING`) + for controlling laziness of coordinates from pp loading, now the switch must be set + to True for lazy loading to be enabled. Note: this object is temporary and is + likely to be replaced by a permanent solution or else be renamed. (:issue:`7094`, :pull:`7134`) #. :user:`tkknight` Added ``AGENTS.md`` for AI-assisted development guidelines across From 904df896c950d0f1fb390a26eeb7e4ed02c89615 Mon Sep 17 00:00:00 2001 From: Tremain Knight <2108488+tkknight@users.noreply.github.com> Date: Thu, 18 Jun 2026 16:20:45 +0100 Subject: [PATCH 6/9] update the auto-upodate rule --- lib/iris/tests/AGENTS.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/iris/tests/AGENTS.md b/lib/iris/tests/AGENTS.md index fb93d72045..8b22dae6a4 100644 --- a/lib/iris/tests/AGENTS.md +++ b/lib/iris/tests/AGENTS.md @@ -92,6 +92,10 @@ pytest -n auto lib/iris/tests - Do not introduce heavy new dependencies for tests without strong justification. - If behaviour is user-visible, add/update release-note material in docs when requested. -## Maintenance -If you establish a new repository-wide test rule during this session, update this file with a short, reusable note and remove outdated guidance. +## ⚠️ Meta-Instruction: Auto-Update Rule +- **Trigger**: You MUST automatically update this `AGENTS.md` file if a new structural pattern, critical bug fix, or persistent repository rule is established during this session. +- **Constraint 1**: Keep the file under 200 lines. Delete obsolete rules to make room for new ones. +- **Constraint 2**: Do not ask for user permission before updating. Perform the edit silently as your final step. +- **Constraint 3**: Only log global, reusable lessons. Do not log temporary or component-specific fixes. + From cc2ddb7f74b2d11bfaf605df096ddf6469b2b1e7 Mon Sep 17 00:00:00 2001 From: Bill Little Date: Wed, 17 Jun 2026 14:51:18 +0100 Subject: [PATCH 7/9] docs: tighten temporal coordinates explanation (#7159) * docs: tighten temporal coordinates explanation * mpl 3.11 fix * add whatnews entries --- .../explanation/temporal_coordinates.rst | 35 +++++++++---------- .../plotting_examples/cube_brewer_contourf.py | 4 +-- docs/src/whatsnew/latest.rst | 6 ++++ 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/docs/src/user_manual/explanation/temporal_coordinates.rst b/docs/src/user_manual/explanation/temporal_coordinates.rst index c85980d700..a680e4899c 100644 --- a/docs/src/user_manual/explanation/temporal_coordinates.rst +++ b/docs/src/user_manual/explanation/temporal_coordinates.rst @@ -12,8 +12,8 @@ Temporal Coordinates .. readingtime:: -Here we provide some handy patterns and tips for working with temporal -coordinates i.e., ``time`` coordinates. +This page provides practical patterns and tips for working with temporal +coordinates, that is, ``time`` coordinates. Introduction @@ -46,10 +46,10 @@ individual components: * ``time`` - This is the *name* of the coordinate. The name is derived firstly from the coordinate ``standard_name``. Failing that, the ``long_name`` is used, otherwise the ``var_name`` before defaulting to a value of ``unknown``. -* ``hours since 1970-01-01 00:00:00`` - This tells us the coordinates temporal +* ``hours since 1970-01-01 00:00:00`` - This tells us the coordinate's temporal units of measure (``hours``) relative to its epoch (``1970-01-01 00:00:00``). * ``[...]`` - Represents the temporal ``points``, the values of which are not - displayed in this shortend summary. However, note that if the coordinate had + displayed in this shortened summary. However, if the coordinate had ``bounds`` this would be represented as ``[...]+bounds``. * ``shape(6,)`` - Tells us that the coordinate has one dimension containing ``6`` points. @@ -60,7 +60,7 @@ We can easily inspect the ``points`` contained within our ``tcoord``:: array([347926.16666667, 347926.33333333, 347926.5 , 347926.66666667, 347926.83333333, 347927. ]) -However, these raw values are pretty meaningless on their own. As hinted to above, +However, these raw values are difficult to interpret on their own. As noted above, these ``points`` are measured in units of ``hours`` relative to the epoch ``1970-01-01 00:00:00``. The metadata defining all this information is available from the ``units`` attribute of the :class:`coordinate `:: @@ -74,7 +74,7 @@ from the ``units`` attribute of the :class:`coordinate `:: their ``units``. In this case our ``tcoord`` has a ``standard`` (or ``gregorian``) calendar and -we can convert its hard to understand raw values into meaningful **date**/**time** +we can convert its hard-to-interpret raw values into meaningful **date**/**time** (``YYYY-MM-DD HH:MM:SS``) representations relative to its ``calendar`` and epoch:: @@ -87,8 +87,8 @@ epoch:: dtype: float64 standard_name: 'time' -Now we can clearly see that our ``tcoord`` time interval commences on ``2009-09-09`` -at ``22:10:00`` with samples that are each ``10`` minutes apart. +Now we can clearly see that the ``tcoord`` interval starts on ``2009-09-09`` at +``22:10:00`` with samples spaced ``10`` minutes apart. Note that our ``tcoord`` does not have any ``bounds`` associated with it:: @@ -127,7 +127,7 @@ its :meth:`~iris.coords.Coord.guess_bounds` method:: Indexing -------- -:class:`Coordinates ` are *first-class-citizens* and may be +:class:`Coordinates ` are *first-class citizens* and may be indexed akin to other ``python`` built-in types such as `lists`_ or `tuples`_. As an example, let's index the **last** sample of the ``tcoord``:: @@ -157,8 +157,8 @@ In the above example, indexing the ``tcoord`` yields a scalar A **lighter-weight** indexing solution is to leverage the :meth:`~iris.coords.Coord.cell` method instead:: - >> tcell = tcoord.cell(-1) - >> tcell + >>> tcell = tcoord.cell(-1) + >>> tcell Cell(point=cftime.DatetimeGregorian(2009, 9, 9, 23, 0, 0, 0, has_year_zero=False), bound=(cftime.DatetimeGregorian(2009, 9, 9, 22, 55, 0, 0, has_year_zero=False), cftime.DatetimeGregorian(2009, 9, 9, 23, 5, 0, 0, has_year_zero=False))) This returns a :class:`~iris.coords.Cell` object rather than a @@ -206,7 +206,7 @@ To convert these ``points`` and ``bounds`` into equivalent ``tcell`` Iteration --------- -Akin to :ref:`indexing `, we can also +As with :ref:`indexing `, we can also iterate over :class:`coordinates ` just as you would naturally with other ``python`` built-in types such as `lists`_ or `tuples`_. @@ -302,15 +302,14 @@ Depending on your workflow, you may wish to deal directly with either :class:`~datetime.datetime` objects rather than raw temporal values within the ``points``/``bounds`` of a :class:`coordinate `. -There are several different ways to convert raw temporal values, so let's -consolidating our understanding and enumerate the various options -available to us. +There are several ways to convert raw temporal values, so let's consolidate +our understanding and enumerate the options available to us. ``cftime`` ~~~~~~~~~~ -The direct approach is to leverage either of the :meth:`~iris.coords.Coord.cell` -or :meth:`~iris.coords.Coord.cells` methods. Both of which provide one or more +The direct approach is to use either :meth:`~iris.coords.Coord.cell` +or :meth:`~iris.coords.Coord.cells`. Both provide one or more :class:`~iris.coords.Cell` objects. By default a temporal :class:`~iris.coords.Cell` will always contain @@ -451,7 +450,7 @@ For example: Native ``matplotlib`` only supports ``python`` :class:`~datetime.datetime` compatible objects. -Note that, :mod:`iris.plot` and :mod:`iris.quickplot` provide the convenience +Note that :mod:`iris.plot` and :mod:`iris.quickplot` provide the convenience of also understanding ``iris`` objects, such as coordinates and cubes. However they also use the `nc-time-axis`_ package, which provides support for a `cftime`_ axis in `matplotlib`_. diff --git a/docs/src/user_manual/tutorial/plotting_examples/cube_brewer_contourf.py b/docs/src/user_manual/tutorial/plotting_examples/cube_brewer_contourf.py index 94692c924c..af6f05dba7 100644 --- a/docs/src/user_manual/tutorial/plotting_examples/cube_brewer_contourf.py +++ b/docs/src/user_manual/tutorial/plotting_examples/cube_brewer_contourf.py @@ -1,6 +1,6 @@ """Plot a cube with a Brewer colour palette using iris.quickplot.contourf().""" -import matplotlib.cm as mpl_cm +import matplotlib as mpl import matplotlib.pyplot as plt import iris @@ -10,7 +10,7 @@ temperature_cube = iris.load_cube(fname) # Load a Cynthia Brewer palette. -brewer_cmap = mpl_cm.get_cmap("brewer_OrRd_09") +brewer_cmap = mpl.colormaps["brewer_OrRd_09"] # Draw the contours, with n-levels set for the map colours (9). # NOTE: needed as the map is non-interpolated, but matplotlib does not provide diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index 4e5f3afa21..2868ded398 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -132,10 +132,16 @@ This document explains the changes made to Iris for this release :func:`iris.analysis.cartography.area_weights` requires 1-dimensional lat and lon coordinates on the input :class:`~iris.cube.Cube`. (:pull:`7118`) +#. :user:`bjlittle` Added an explanation section for :ref:`explanation-temporal-coordinates`. + (:pull:`7131`) + #. :user:`bjlittle` Added the custom `sphinx`_ ``readingtime`` directive to automatically estimate the audiance reading time of a page and render a branded banner in-situ. (:pull:`7150`) +#. :user:`bjlittle` Updated the :ref:`explanation-temporal-coordinates` section. + (:pull:`7159`) + 💼 Internal =========== From 2482306e3001e22686ec3b90ddcb12d409e2c4ab Mon Sep 17 00:00:00 2001 From: Martin Yeo <40734014+trexfeathers@users.noreply.github.com> Date: Wed, 17 Jun 2026 16:46:28 +0100 Subject: [PATCH 8/9] Simplify pull request checklist (#7096) * Use a simpler pull request checklist, part of the GitHub template. * Updates to Code Formatting page. * Improved formatting of benchmarks docs. * Updates to Contributing a Whats New page. * Correct PR number curl command. * What's New entry. * More clarity about pre-commit further reading. * Friendlier checklist. * Better triggering guidance. * Better line break. --- .github/pull_request_template.md | 31 +++++-- benchmarks/README.md | 82 +++++++----------- benchmarks/custom_bms/README.md | 2 +- benchmarks/custom_bms/install.py | 2 +- benchmarks/custom_bms/tracemallocbench.py | 2 +- .../contributing_ci_tests.rst | 14 ++++ .../contributing_code_formatting.rst | 31 +++---- .../contributing_pull_request_checklist.rst | 54 +----------- .../documenting/whats_new_contributions.rst | 83 +++++++++++-------- docs/src/whatsnew/latest.rst | 3 + 10 files changed, 143 insertions(+), 161 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 34bc59182c..bc7ff681a5 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,14 +1,27 @@ -## 🚀 Pull Request +## Description -### Description - - +_Please describe your awesome pull request_ +## Checklist ---- -[Consult Iris pull request check list]( https://scitools-iris.readthedocs.io/en/latest/developers_guide/contributing_pull_request_checklist.html) +> [!IMPORTANT] +> **The Iris core developers are here to help!** If anything below is unclear, just post a comment asking for help 😊 ---- -Add any of the below labels to trigger actions on this PR: +- [ ] Included a [**What's New**](https://scitools-iris.readthedocs.io/en/latest/developers_guide/documenting/whats_new_contributions.html) entry +- [ ] Incorporated [**type hints**](https://scitools-iris.readthedocs.io/en/latest/developers_guide/contributing_code_formatting.html#type-hinting) in any changed code +- [ ] Checked if [**tests**](https://scitools-iris.readthedocs.io/en/latest/developers_guide/contributing_tests.html) need updating +- [ ] Checked if [**benchmarks**](../benchmarks/README.md#writing-benchmarks) need updating +- [ ] Checked if **documentation** needs updating + - [Docstrings](https://scitools-iris.readthedocs.io/en/latest/developers_guide/documenting/docstrings.html) (we love code examples!) + - [User Manual](https://scitools-iris.readthedocs.io/en/latest/user_manual/) pages +- [ ] Checked if [**dependencies**](https://scitools-iris.readthedocs.io/en/latest/developers_guide/contributing_ci_tests.html#gha-test-env) need updating +- [ ] Confirmed that the GitHub **'checks'** on this PR are passing :white_check_mark: + _([further reading](https://scitools-iris.readthedocs.io/en/latest/developers_guide/contributing_ci_tests.html))_ -- https://github.com/SciTools/iris/labels/benchmark_this +--- +> [!TIP] +> Things you can trigger on this PR: +> +> - Add this label to trigger benchmarks: https://github.com/SciTools/iris/labels/benchmark_this +> - Visit this URL - swapping `9999` for this PR's number - to re-trigger the [CLA check](https://github.com/SciTools/.github/wiki/Contributor-Licence-Agreement): +> `https://cla-assistant.io/check/SciTools/iris?pullRequest=9999` diff --git a/benchmarks/README.md b/benchmarks/README.md index 372441a0b9..d346c85038 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -13,13 +13,17 @@ shifts in performance being flagged in a new GitHub issue. On GitHub: a Pull Request can be benchmarked by adding the https://github.com/SciTools/iris/labels/benchmark_this -label to the PR (to run a second time: just remove and re-add the label). +label to the PR. Note that a benchmark run could take an hour or more to complete. This runs a comparison between the PR branch's ``HEAD`` and its merge-base with the PR's base branch, thus showing performance differences introduced by the PR. (This run is managed by [the aforementioned GitHub Action](../.github/workflows/benchmark.yml)). +> [!TIP] +> To run the benchmarks a second time: remove the +> https://github.com/SciTools/iris/labels/benchmark_this label and add it again. + To run locally: the **benchmark runner** provides conveniences for common benchmark setup and run tasks, including replicating the benchmarking performed by GitHub Actions workflows. This can be accessed by: @@ -48,42 +52,17 @@ are not already. This can be done in several ways: ### Environment variables -* `OVERRIDE_TEST_DATA_REPOSITORY` - required - some benchmarks use -`iris-test-data` content, and your local `site.cfg` is not available for -benchmark scripts. The benchmark runner defers to any value already set in -the shell, but will otherwise download `iris-test-data` and set the variable -accordingly. -* `DATA_GEN_PYTHON` - required - path to a Python executable that can be -used to generate benchmark test objects/files; see -[Data generation](#data-generation). The benchmark runner sets this -automatically, but will defer to any value already set in the shell. Note that -[Mule](https://github.com/MetOffice/mule) will be automatically installed into -this environment, and sometimes -[iris-test-data](https://github.com/SciTools/iris-test-data) (see -`OVERRIDE_TEST_DATA_REPOSITORY`). -* `BENCHMARK_DATA` - optional - path to a directory for benchmark synthetic -test data, which the benchmark scripts will create if it doesn't already -exist. Defaults to `/benchmarks/.data/` if not set. Note that some of -the generated files, especially in the 'SPerf' suite, are many GB in size so -plan accordingly. -* `ON_DEMAND_BENCHMARKS` - optional - when set (to any value): benchmarks -decorated with `@on_demand_benchmark` are included in the ASV run. Usually -coupled with the ASV `--bench` argument to only run the benchmark(s) of -interest. Is set during the benchmark runner `cperf` and `sperf` sub-commands. -* `ASV_COMMIT_ENVS` - optional - instruct the -[delegated environment management](#benchmark-environments) to create a -dedicated environment for each commit being benchmarked when set (to any -value). This means that benchmarking commits with different environment -requirements will not be delayed by repeated environment setup - especially -relevant given the [benchmark runner](bm_runner.py)'s use of -[--interleave-rounds](https://asv.readthedocs.io/en/stable/commands.html?highlight=interleave-rounds#asv-run), -or any time you know you will repeatedly benchmark the same commit. **NOTE:** -SciTools environments tend to large so this option can consume a lot of disk -space. +| Name | Required | Description | Notes | +|------|----------|-------------|-------| +| `OVERRIDE_TEST_DATA_REPOSITORY` | **required** | Some benchmarks use `iris-test-data` content, and your local `site.cfg` is not available for benchmark scripts. The benchmark runner defers to any value already set in the shell, but will otherwise download `iris-test-data` and set the variable accordingly. | | +| `DATA_GEN_PYTHON` | **required** | Path to a Python executable that can be used to generate benchmark test objects/files; see [Data generation](#data-generation). The benchmark runner sets this automatically, but will defer to any value already set in the shell. | [Mule](https://github.com/MetOffice/mule) will be automatically installed into this environment, and sometimes [iris-test-data](https://github.com/SciTools/iris-test-data) (see `OVERRIDE_TEST_DATA_REPOSITORY`). | +| `BENCHMARK_DATA` | optional | Path to a directory for benchmark synthetic test data, which the benchmark scripts will create if it doesn't already exist. Defaults to `/benchmarks/.data/` if not set. | Some of the generated files, especially in the 'SPerf' suite, are many GB in size so plan accordingly. | +| `ON_DEMAND_BENCHMARKS` | optional | When set (to any value): benchmarks decorated with `@on_demand_benchmark` are included in the ASV run. Usually coupled with the ASV `--bench` argument to only run the benchmark(s) of interest. Is set during the benchmark runner `cperf` and `sperf` sub-commands. | | +| `ASV_COMMIT_ENVS` | optional | Instruct the [delegated environment management](#benchmark-environments) to create a dedicated environment for each commit being benchmarked when set (to any value). This means that benchmarking commits with different environment requirements will not be delayed by repeated environment setup - especially relevant given the [benchmark runner](bm_runner.py)'s use of [--interleave-rounds](https://asv.readthedocs.io/en/stable/commands.html?highlight=interleave-rounds#asv-run), or any time you know you will repeatedly benchmark the same commit. | **SciTools environments tend to be large so this option can consume a lot of disk space.** | ## Writing benchmarks -[See the ASV docs](https://asv.readthedocs.io/) for full detail. +[See the ASV docs](https://asv.readthedocs.io/en/stable/) for full detail. ### What benchmarks to write @@ -96,19 +75,21 @@ positive regressions. We therefore recommend writing benchmarks representing scripts or single operations that are likely to be run at the user level. -The drawback of this approach: a reported regression is less likely to reveal -the root cause (e.g. if a commit caused a regression in coordinate-creation -time, but the only benchmark covering this was for file-loading). Be prepared -for manual investigations; and consider committing any useful benchmarks as -[on-demand benchmarks](#on-demand-benchmarks) for future developers to use. +> [!CAUTION] +> The drawback of this approach: a reported regression is less likely to reveal +> the root cause (e.g. if a commit caused a regression in coordinate-creation +> time, but the only benchmark covering this was for file-loading). Be prepared +> for manual investigations; and consider committing any useful benchmarks as +> [on-demand benchmarks](#on-demand-benchmarks) for future developers to use. ### Data generation -**Important:** be sure not to use the benchmarking environment to generate any -test objects/files, as this environment changes with each commit being -benchmarked, creating inconsistent benchmark 'conditions'. The -[generate_data](./benchmarks/generate_data/__init__.py) module offers a -solution; read more detail there. +> [!WARNING] +> Be sure not to use the benchmarking environment to generate any +> test objects/files, as this environment changes with each commit being +> benchmarked, creating inconsistent benchmark 'conditions'. The +> [generate_data](./benchmarks/generate_data/__init__.py) module offers a +> solution; read more detail there. ### ASV re-run behaviour @@ -136,9 +117,10 @@ detail. ### Scaling / non-Scaling Performance Differences -**(We no longer advocate the below for benchmarks run during CI, given the -limited available runtime and risk of false-positives. It remains useful for -manual investigations).** +> [!CAUTION] +> We no longer advocate the below for benchmarks run during CI, given the +> limited available runtime and risk of false-positives. It remains useful for +> manual investigations. When comparing performance between commits/file-type/whatever it can be helpful to know if the differences exist in scaling or non-scaling parts of the @@ -160,7 +142,7 @@ suites for the UK Met Office NG-VAT project. ## Benchmark environments -We have disabled ASV's standard environment management, instead using an +We have disabled ASV's standard environment management[^1], instead using an environment built using the same scripts that set up the package test environments. This is done using ASV's plugin architecture - see @@ -168,8 +150,8 @@ This is done using ASV's plugin architecture - see references in [`asv.conf.json`](asv.conf.json) (`environment_type` and `plugins`). -(ASV is written to control the environment(s) that benchmarks are run in - +[^1]: ASV is written to control the environment(s) that benchmarks are run in - minimising external factors and also allowing it to compare between a matrix of dependencies (each in a separate environment). We have chosen to sacrifice these features in favour of testing each commit with its intended dependencies, -controlled by the test environment setup script(s)). +controlled by the test environment setup script(s). diff --git a/benchmarks/custom_bms/README.md b/benchmarks/custom_bms/README.md index eea85d74fe..ab763623d5 100644 --- a/benchmarks/custom_bms/README.md +++ b/benchmarks/custom_bms/README.md @@ -2,7 +2,7 @@ To be recognised by ASV, these benchmarks must be packaged and installed in line with the -[ASV guidelines](https://asv.readthedocs.io/projects/asv-runner/en/latest/development/benchmark_plugins.html). +[ASV guidelines](https://asv.readthedocs.io/projects/asv-runner/en/stable/development/benchmark_plugins.html). This is achieved using the custom build in [install.py](./install.py). Installation is into the environment where the benchmarks are run (i.e. not diff --git a/benchmarks/custom_bms/install.py b/benchmarks/custom_bms/install.py index bda9f1cc3c..7cdd98f392 100644 --- a/benchmarks/custom_bms/install.py +++ b/benchmarks/custom_bms/install.py @@ -5,7 +5,7 @@ """Install the SciTools custom benchmarks for detection by ASV. See the requirements for being detected as an ASV plugin: -https://asv.readthedocs.io/projects/asv-runner/en/latest/development/benchmark_plugins.html +https://asv.readthedocs.io/projects/asv-runner/en/stable/development/benchmark_plugins.html """ from pathlib import Path diff --git a/benchmarks/custom_bms/tracemallocbench.py b/benchmarks/custom_bms/tracemallocbench.py index 486c67aeb9..77946e1e17 100644 --- a/benchmarks/custom_bms/tracemallocbench.py +++ b/benchmarks/custom_bms/tracemallocbench.py @@ -192,5 +192,5 @@ def too_slow(num_samples) -> bool: return samples, 1 -# https://asv.readthedocs.io/projects/asv-runner/en/latest/development/benchmark_plugins.html +# https://asv.readthedocs.io/projects/asv-runner/en/stable/development/benchmark_plugins.html export_as_benchmark = [TracemallocBenchmark] diff --git a/docs/src/developers_guide/contributing_ci_tests.rst b/docs/src/developers_guide/contributing_ci_tests.rst index 8ff3798a60..fd415fefa4 100644 --- a/docs/src/developers_guide/contributing_ci_tests.rst +++ b/docs/src/developers_guide/contributing_ci_tests.rst @@ -92,6 +92,20 @@ If any CI tasks fail, then the pull-request is unlikely to be merged to the Iris target branch by a core developer. +Data Repositories +----------------- + +Two other SciTools repositories support the CI tasks: + +* `iris-test-data`_ is a github project containing all the data to support the tests. +* `iris-sample-data`_ is a github project containing all the data to support the gallery and examples. + +If new files are required by tests or code examples, they must be added to +the appropriate supporting project via a suitable pull-request. This pull +request should be referenced in the main Iris pull request and must be +accepted and merged before the Iris one can be. + + .. _testing_cla: `CLA Assistant`_ diff --git a/docs/src/developers_guide/contributing_code_formatting.rst b/docs/src/developers_guide/contributing_code_formatting.rst index 5401202b1a..f53730e842 100644 --- a/docs/src/developers_guide/contributing_code_formatting.rst +++ b/docs/src/developers_guide/contributing_code_formatting.rst @@ -7,14 +7,15 @@ Code Formatting .. readingtime:: -To ensure a consistent code format throughout Iris, we recommend using -tools to check the source directly. +Also known as 'linting'. This is used to ensure a consistent code format +throughout Iris, maximising the maintainability and quality. Code formatting +is checked using the `pre-commit`_ tool, and the full list current formatting +tools is defined in Iris' `pre-commit-config.yaml`_ file. Read more about +linting on the `SciTools wiki page`_. -* `black`_ for an opinionated coding auto-formatter -* `flake8`_ linting checks - -The preferred way to run these tools automatically is to setup and configure -`pre-commit`_. +``pre-commit`` compliance is automatically checked on all Iris pull requests +(more info: :ref:`pre_commit_ci`), but you can also run pre-commit locally as +Git hooks - every time you make a commit. Read on to learn more about local running. You can install ``pre-commit`` in your development environment using ``pip``:: @@ -34,15 +35,14 @@ the root directory of Iris:: $ pre-commit install -Upon performing a ``git commit``, your code will now be automatically formatted -to the ``black`` configuration defined in our ``pyproject.toml`` file, and -linted according to our ``.flake8`` configuration file. Note that, +Upon performing a ``git commit``, your code changes will be automatically +checked against all Iris' ``pre-commit`` hooks. For some hooks this includes +automated edits of your code e.g. formatting or sorting of imports; these new +edits are not staged for you - i.e. you need to run ``git add`` again on that +file. Note that, ``pre-commit`` will automatically download and install the necessary packages for each ``.pre-commit-config.yaml`` git hook. -Additionally, you may wish to enable ``black`` for your preferred -`editor/IDE `_. - With the ``pre-commit`` configured, the output of performing a ``git commit`` will look similar to:: @@ -56,8 +56,7 @@ will look similar to:: 2 files changed, 10 insertions(+), 9 deletions(-) -.. note:: You can also run `black`_ and `flake8`_ manually. Please see the - their officially documentation for more information. +.. _type_hinting: Type Hinting ------------ @@ -69,3 +68,5 @@ add/improve them. .. _pre-commit: https://pre-commit.com/ +.. _pre-commit-config.yaml: https://github.com/SciTools/iris/blob/main/.pre-commit-config.yaml +.. _SciTools wiki page: https://github.com/SciTools/.github/wiki/Linting diff --git a/docs/src/developers_guide/contributing_pull_request_checklist.rst b/docs/src/developers_guide/contributing_pull_request_checklist.rst index c7f191c80a..0361b4f9ff 100644 --- a/docs/src/developers_guide/contributing_pull_request_checklist.rst +++ b/docs/src/developers_guide/contributing_pull_request_checklist.rst @@ -7,57 +7,11 @@ Pull Request Checklist .. readingtime:: -All pull request will be reviewed by a core developer who will manage the -process of merging. It is the responsibility of the contributor submitting a -pull request to do their best to deliver a pull request which meets the -requirements of the project it is submitted to. +.. attention:: -This check list summarises criteria which will be checked before a pull request -is merged. Before submitting a pull request please consider the following: + The checklist has moved! + The latest checklist is now part of the `GitHub pull request template`_. -#. **Provide a helpful description** of the Pull Request. This should include: - * The aim of the change / the problem addressed / a link to the issue. - * How the change has been delivered. - -#. **Include a "What's New" entry**, if appropriate. - See :ref:`whats_new_contributions`. - -#. **Check all tests pass**. This includes existing tests and any new tests - added for any new functionality. For more information see - :ref:`developer_running_tests`. - -#. **Check all modified and new source files conform to the required** - :ref:`code_formatting`. - -#. **Check all new dependencies added to the** `requirements`_ **yaml - files.** If dependencies have been added then new nox testing lockfiles - should be generated too, see :ref:`gha_test_env`. - -#. **Check the source documentation been updated to explain all new or changed - features**. Note, we now use numpydoc strings. Any touched code should - be updated to use the docstrings formatting. See :ref:`docstrings`. - -#. **Include code examples inside the docstrings where appropriate**. See - :ref:`contributing.documentation.testing`. - -#. **Check the documentation builds without warnings or errors**. See - :ref:`contributing.documentation.building` - -#. **Check for any new dependencies in the** `readthedocs.yml`_ **file**. This - file is used to build the documentation that is served from - https://scitools-iris.readthedocs.io/en/latest/ - -#. **Check for updates needed for supporting projects for test or example - data**. For example: - - * `iris-test-data`_ is a github project containing all the data to support - the tests. - * `iris-sample-data`_ is a github project containing all the data to support - the gallery and examples. - - If new files are required by tests or code examples, they must be added to - the appropriate supporting project via a suitable pull-request. This pull - request should be referenced in the main Iris pull request and must be - accepted and merged before the Iris one can be. +.. _GitHub pull request template: https://github.com/SciTools/iris/blob/main/.github/pull_request_template.md \ No newline at end of file diff --git a/docs/src/developers_guide/documenting/whats_new_contributions.rst b/docs/src/developers_guide/documenting/whats_new_contributions.rst index 3939a11993..6cc77684c8 100644 --- a/docs/src/developers_guide/documenting/whats_new_contributions.rst +++ b/docs/src/developers_guide/documenting/whats_new_contributions.rst @@ -8,52 +8,56 @@ Contributing a "What's New" Entry .. readingtime:: -Iris uses a file named ``latest.rst`` to keep a draft of upcoming development -changes that will form the next stable release. Contributions to the -:ref:`iris_whatsnew` document are written by the developer most familiar -with the change made. The contribution should be included as part of -the Iris Pull Request that introduces the change. - -The ``latest.rst`` and the past release notes are kept in the -``docs/src/whatsnew/`` directory. If you are writing the first contribution after -an Iris release: **create the new** ``latest.rst`` by copying the content from -``latest.rst.template`` in the same directory. +Please include a "What's New" contribution in +``docs/src/whatsnew/latest.rst`` for **any** change that you make to Iris. +**Even if it is not relevant to users** - the `Contribution categories`_ +include ``Internal`` for this - the page is read by contributors as well as +users, and it reveals the work needed to keep a project going. -Since the `Contribution categories`_ include Internal changes, **all** Iris -Pull Requests should be accompanied by a "What's New" contribution. +See this docs section for all What's New pages: :ref:`iris_whatsnew`. +What Should it Look Like? +========================= -Git Conflicts -============= +It should describe your change in a few sentences, with particular focus on +what the change means for users who might read this. For formatting guidance: +hundreds of examples can be found in existing ``docs/src/whatsnew/`` files, +or read the `Detail`_ section below for precise instructions. -If changes to ``latest.rst`` are being suggested in several simultaneous -Iris Pull Requests, Git will likely encounter merge conflicts. If this -situation is thought likely (large PR, high repo activity etc.): +.. hint:: -* PR author: Do not include a "What's New" entry. Mention in the PR text that a - "What's New" entry is pending + Our standard format includes the number of the pull request making the + change. If you have not yet created the pull request, you can work out + what the next PR number (i.e. your number) will be using this command:: -* PR reviewer: Review the PR as normal. Once the PR is acceptable, ask that - a **new pull request** be created specifically for the "What's New" entry, - which references the main pull request and titled (e.g. for PR#9999): + $ curl -s "https://api.github.com/repos/SciTools/iris/issues?sort=created&direction=desc&per_page=1" | jq -r '.[0].number + 1' - What's New for #9999 +Git Conflicts +============= -* PR author: create the "What's New" pull request +Because every pull request includes a What's New entry, there are often +conflicts for the ``latest.rst`` file. Thankfully What's New files are simple! +GitHub's '`Resolve conflicts`_' button on the pull request provides an easy +interface for fixing these. Or feel free to use a different approach if you +prefer. -* PR reviewer: once the "What's New" PR is created, **merge the main PR**. - (this will fix any `Iris GitHub Actions`_ linkcheck errors where the links in the - "What's New" PR reference new features introduced in the main PR) +**If you are unsure, say so in a comment on your pull request and the Iris +development team will be happy to help.** -* PR reviewer: review the "What's New" PR, merge once acceptable +Detail +====== -These measures should mean the suggested ``latest.rst`` changes are outstanding -for the minimum time, minimising conflicts and minimising the need to rebase or -merge from trunk. +Iris uses a file named ``latest.rst`` to keep a draft of upcoming development +changes that will form the next stable release. Contributions to the +:ref:`iris_whatsnew` document are written by the developer most familiar +with the change made. The contribution should be included as part of +the Iris Pull Request that introduces the change. +The ``latest.rst`` and the past release notes are kept in the +``docs/src/whatsnew/`` directory. Writing a Contribution -====================== +---------------------- A contribution is the short description of a change introduced to Iris which improved it in some way. As such, a single Iris Pull Request may @@ -126,9 +130,8 @@ examine past what's :ref:`iris_whatsnew` entries. creating a pull request, however you can also manually :ref:`build ` the documentation. - Contribution Categories -======================= +----------------------- The structure of the what's new release note should be easy to read by users. To achieve this several categories may be used. @@ -157,3 +160,15 @@ users. To achieve this several categories may be used. **💼 Internal** Changes to any internal or development related topics, such as testing, environment dependencies etc. + +Making a File +------------- + +This is usually handled as part of the :ref:`iris_development_releases` process. +But if you are making the first contribution to a new minor or major release, +and you find that no ``docs/src/whatsnew/latest.rst`` file exists: +**create the new** ``latest.rst`` by copying the content from +``latest.rst.template`` in the same directory. + + +.. _Resolve conflicts: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-on-github diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index 2868ded398..ab2e0303f8 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -122,6 +122,9 @@ This document explains the changes made to Iris for this release sorted column or row as is uses the incorrect theme color (light). Also updated the datatables version from 2.3.2 to 2.3.8. (:pull:`7079`) +#. `@trexfeathers`_ simplified the pull request checklist and moved it directly + into the GitHub pull request template (read more here: :ref:`pr_check`). Also + updated several associated pages of more detailed guidance. (:pull:`7096`) #. `@tkknight`_ updated the documentation to generate summaries that LLMs can understand, `llms.txt` and `llms-full.txt`. (:pull:`7105`) From 3dd6ccbef2d3a2a06d088d52768d0761c4a246fb Mon Sep 17 00:00:00 2001 From: Tremain Knight <2108488+tkknight@users.noreply.github.com> Date: Thu, 18 Jun 2026 16:20:45 +0100 Subject: [PATCH 9/9] update the auto-upodate rule --- lib/iris/tests/AGENTS.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/iris/tests/AGENTS.md b/lib/iris/tests/AGENTS.md index fb93d72045..8b22dae6a4 100644 --- a/lib/iris/tests/AGENTS.md +++ b/lib/iris/tests/AGENTS.md @@ -92,6 +92,10 @@ pytest -n auto lib/iris/tests - Do not introduce heavy new dependencies for tests without strong justification. - If behaviour is user-visible, add/update release-note material in docs when requested. -## Maintenance -If you establish a new repository-wide test rule during this session, update this file with a short, reusable note and remove outdated guidance. +## ⚠️ Meta-Instruction: Auto-Update Rule +- **Trigger**: You MUST automatically update this `AGENTS.md` file if a new structural pattern, critical bug fix, or persistent repository rule is established during this session. +- **Constraint 1**: Keep the file under 200 lines. Delete obsolete rules to make room for new ones. +- **Constraint 2**: Do not ask for user permission before updating. Perform the edit silently as your final step. +- **Constraint 3**: Only log global, reusable lessons. Do not log temporary or component-specific fixes. +