What’s New in Iris#

v3.16 (13 Aug 2026)#

This document explains the changes made to Iris for this release (View all changes.)

v3.16 Release Highlights

The highlights for this minor release of Iris include:

  • Introduced the function guess_2D_bounds() for guessing the bounds of pairs of 2D coordinates.

  • Improved NetCDF character-array handling so Iris now supports string data in cube data arrays.

  • Added support for loading and saving of Zarr files formatted in Zarr Storage Spec Version 2 via the NetCDF NCZarr implementation.

  • Improved the speed of field iteration when reading PP files. Up to 3x speed up has been seen, depending on the circumstances.

  • Special shoutout to @pt331 for their work on the release while deployed into the core development team.

  • We also want to thank @gaoflow, @2319bli, @GitRylee, @king56180468-droid, @SgtVarmint for their contributions that have gone into this release.

And finally, get in touch with us on GitHub if you have any issues or feature requests for improving Iris. Enjoy!

✨ Features#

🐛 Bugs Fixed#

  • #7119: @gaoflow fixed iris.analysis.cartography.wrap_lons() so that it preserves the floating-point dtype of its input (e.g. float32) instead of always promoting the result to float64. Integer inputs are still returned as float64. ( #4119)

  • #7120: @gaoflow fixed iris.coords.Coord.cell() so that a masked bound is preserved as masked, instead of revealing the value stored underneath the mask. This also corrects the cube/coordinate printout for such bounds. ( #5158)

  • #7121: @gaoflow made iris.Constraint raise a TypeError when used in a boolean context (e.g. with the and/or/not keywords) instead of silently discarding one of the constraints. Use the & operator to combine constraints. ( #4337)

  • #7122: @gaoflow fixed coordinate summaries so that length-0 string and date-like coordinates print as empty arrays instead of raising ValueError. ( #6531)

  • #7123: @gaoflow fixed iris.cube.Cube.rolling_window() so that it no longer raises a TypeError when the cube has a lazy auxiliary coordinate along the windowed dimension. ( #6480)

  • #7124: @gaoflow fixed regridding so that horizontal coordinates of the result cube are copies of, rather than references to, the target grid’s coordinates. Previously, modifying a result coordinate also modified the target cube’s coordinate, and vice versa. ( #6844)

  • #7125: @gaoflow fixed iris.cube.CubeList.concatenate() so that cubes with string coordinates of differing width, such as dtypes <U1 and <U5, can be concatenated. The result coordinate is promoted to the wider dtype. ( #6676)

  • #7126: @gaoflow fixed an error when computing (e.g. saving) a scalar lazy cube whose units had been converted with convert_units(). The unit conversion could yield a plain Python scalar for the 0-dimensional block, which Dask was then unable to store. ( #6965)

  • #7197: @trexfeathers and @kwilliams-mo fixed the saving of PP fields to now always write lbft in hours in the no-bounds forecast period case, including when forecast_period uses non-hour units such as seconds.

💣 Incompatible Changes#

🚀 Performance Enhancements#

  • #7089: @trexfeathers improved the speed of field iteration when reading PP files. Up to 3x speed up has been seen, dependending on the circumstances.

🔥 Deprecations#

🔗 Dependencies#

  • #7053: @trexfeathers and @tkknight removed the maximum pin for the PyData Sphinx Theme (used in the docs). ( #6885)

  • #7060: @tkknight added a minimum pin for the PyData Sphinx Theme as we use the collapse sidebar feature introduced in 0.17.0.

  • #7084: @tkknight updated a dependency in the Read The Docs configuration file to use the latest python.

  • #7100: @tkknight added a dependency named sphinx-sitemap to generate sitemap.xml for the documentation.

  • #7105: @tkknight added a dependency named sphinx-llm to generate summaries that LLMs can understand, llms.txt and llms-full.txt.

  • #7223: @trexfeathers updated Iris to be compatible with Matplotlib version 3.11.

📚 Documentation#

💼 Internal#

  • #6976: @ESadek-MO and @pp-mo removed unit test reliance on all optional dependencies except for mo_pack. ( #6832)

  • #7036: @trexfeathers altered the messaging for ‘stale’ issues and pull requests, to reduce the negative connotations. We now use needs-checkin for the initial prompt, and not-resourced if the issue/PR ends up closed. ( #6993)

  • #7046: @trexfeathers fixed the benchmarking asv_delegated.py to work with Nox release 2026.04.10 (which adds more files to the environment parent directory, breaking previous assumptions).

  • #7087: @SgtVarmint migrated codebase from os.path to pathlib.Path where possible. ( #4523)

  • #7098: @pp-mo, @trexfeathers, and @ukmo-ccbunney refactored NetCDF character bytecoding into dedicated dataset handlers, added optional load-time string decoding, and enabled saving from either string or character cube content (with explicit string dimensions for char output). ( #6309)

  • #7113: @trexfeathers and @stephenworsley added functionality to the NetCDF loader and saver to handle Zarr file I/O using the NetCDF NCZarr implementation. ( #6967)

  • #7134: @HGWright changed the default of the private switch _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. ( #7094)

  • #7138: @bjlittle and @trexfeathers added the Zizmor pre-commit hook to monitor for security vulnerabilities in Iris’ GitHub Actions workflows, and then actioned Zizmor’s recommendations to harden the workflows.

  • #7148, #7165: @trexfeathers set the link checking workflow to accept redirect HTTP codes, as the reports were getting too noisy.

  • #7163: @rcomer fixed the capitalisation of a pytest marker.

  • #7185: @pt331 and @trexfeathers and @pp-mo improved type hints Type Hinting in iris.common.metadata and iris.mesh.components

  • #7187: @2319bli has removed assignments to class level variables used in test_cell.py. ( #6625)

  • #7188: @GitRylee moved duplicated code in iris.tests.unit.analysis.trajectory.test__nearest_neighbour_indices_ndcoords to a setup fixture. ( #6625)

  • #7189: @king56180468-droid removed redundant commented codes from test_CFReader. ( #6625)

  • #7190: @2319bli has partially improved the names of various test classes. ( #6625)

  • #7203: @bouweandela enabled Ruff type checking (TC) rules.

  • #7206: @tkknight added CLAUDE.md that for now just includes AGENTS.md.