From 03731a4797f835afe8260c6062d7d4d2e6164686 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Sat, 10 Feb 2024 23:45:24 +0000 Subject: [PATCH] replace all warnings --- lib/iris/_concatenate.py | 4 +- lib/iris/_deprecation.py | 4 +- lib/iris/analysis/_regrid.py | 4 +- lib/iris/analysis/calculus.py | 4 +- lib/iris/analysis/cartography.py | 14 +++---- lib/iris/analysis/geometry.py | 10 ++--- lib/iris/analysis/maths.py | 4 +- lib/iris/aux_factory.py | 38 ++++++++--------- lib/iris/config.py | 6 +-- lib/iris/coord_systems.py | 6 +-- lib/iris/coords.py | 10 ++--- lib/iris/cube.py | 6 +-- lib/iris/exceptions.py | 2 +- lib/iris/experimental/regrid.py | 4 +- lib/iris/experimental/ugrid/cf.py | 14 +++---- lib/iris/experimental/ugrid/load.py | 8 ++-- lib/iris/fileformats/_ff.py | 16 ++++---- .../fileformats/_nc_load_rules/actions.py | 6 +-- .../fileformats/_nc_load_rules/helpers.py | 41 ++++++++++--------- lib/iris/fileformats/cf.py | 24 +++++------ lib/iris/fileformats/name_loaders.py | 6 +-- lib/iris/fileformats/netcdf/loader.py | 8 ++-- lib/iris/fileformats/netcdf/saver.py | 18 ++++---- lib/iris/fileformats/nimrod_load_rules.py | 12 +++--- lib/iris/fileformats/pp.py | 12 +++--- lib/iris/fileformats/pp_save_rules.py | 4 +- lib/iris/fileformats/rules.py | 8 ++-- lib/iris/iterate.py | 4 +- lib/iris/pandas.py | 6 +-- lib/iris/plot.py | 6 +-- 30 files changed, 155 insertions(+), 154 deletions(-) diff --git a/lib/iris/_concatenate.py b/lib/iris/_concatenate.py index c6d58b16225..db2ffe3ef4f 100644 --- a/lib/iris/_concatenate.py +++ b/lib/iris/_concatenate.py @@ -9,7 +9,7 @@ """ from collections import defaultdict, namedtuple -import warnings +from iris.exceptions import warn_once_at_level import dask.array as da import numpy as np @@ -998,7 +998,7 @@ def register( raise iris.exceptions.ConcatenateError([msg]) elif not match: msg = f"Found cubes with overlap on concatenate axis {candidate_axis}, skipping concatenation for these cubes" - warnings.warn(msg) + warn_once_at_level(msg) # Check for compatible AuxCoords. if match: diff --git a/lib/iris/_deprecation.py b/lib/iris/_deprecation.py index 73fcedcd828..f04b5987c73 100644 --- a/lib/iris/_deprecation.py +++ b/lib/iris/_deprecation.py @@ -8,7 +8,7 @@ """ -import warnings +from iris.exceptions import warn_once_at_level class IrisDeprecation(UserWarning): @@ -44,7 +44,7 @@ def warn_deprecated(msg, stacklevel=2): >>> """ - warnings.warn(msg, IrisDeprecation, stacklevel=stacklevel) + warn_once_at_level(msg, IrisDeprecation, stacklevel=stacklevel) # A Mixin for a wrapper class that copies the docstring of the wrapped class diff --git a/lib/iris/analysis/_regrid.py b/lib/iris/analysis/_regrid.py index 4592a0ede70..999b8609753 100644 --- a/lib/iris/analysis/_regrid.py +++ b/lib/iris/analysis/_regrid.py @@ -6,7 +6,7 @@ import copy import functools -import warnings +from iris.exceptions import warn_once_at_level import numpy as np import numpy.ma as ma @@ -1136,6 +1136,6 @@ def regrid_reference_surface( "Cannot update aux_factory {!r} because of dropped" " coordinates.".format(factory.name()) ) - warnings.warn(msg) + warn_once_at_level(msg) return result diff --git a/lib/iris/analysis/calculus.py b/lib/iris/analysis/calculus.py index 75b7d864066..a82e8b03b6b 100644 --- a/lib/iris/analysis/calculus.py +++ b/lib/iris/analysis/calculus.py @@ -11,7 +11,7 @@ """ import re -import warnings +from iris.exceptions import warn_once_at_level import cf_units import numpy as np @@ -85,7 +85,7 @@ def _construct_midpoint_coord(coord, circular=None): "Construction coordinate midpoints for the '{}' coordinate, " "though it has the attribute 'circular'={}." ) - warnings.warn(msg.format(circular, coord.circular, coord.name())) + warn_once_at_level(msg.format(circular, coord.circular, coord.name())) if coord.ndim != 1: raise iris.exceptions.CoordinateMultiDimError(coord) diff --git a/lib/iris/analysis/cartography.py b/lib/iris/analysis/cartography.py index 0d17f0b38ae..1243f868419 100644 --- a/lib/iris/analysis/cartography.py +++ b/lib/iris/analysis/cartography.py @@ -10,7 +10,7 @@ from collections import namedtuple import copy -import warnings +from iris.exceptions import warn_once_at_level import cartopy.crs as ccrs import cartopy.img_transform @@ -401,16 +401,16 @@ def area_weights(cube, normalize=False): cs = cube.coord_system("CoordSystem") if isinstance(cs, iris.coord_systems.GeogCS): if cs.inverse_flattening != 0.0: - warnings.warn("Assuming spherical earth from ellipsoid.") + warn_once_at_level("Assuming spherical earth from ellipsoid.") radius_of_earth = cs.semi_major_axis elif isinstance(cs, iris.coord_systems.RotatedGeogCS) and ( cs.ellipsoid is not None ): if cs.ellipsoid.inverse_flattening != 0.0: - warnings.warn("Assuming spherical earth from ellipsoid.") + warn_once_at_level("Assuming spherical earth from ellipsoid.") radius_of_earth = cs.ellipsoid.semi_major_axis else: - warnings.warn("Using DEFAULT_SPHERICAL_EARTH_RADIUS.") + warn_once_at_level("Using DEFAULT_SPHERICAL_EARTH_RADIUS.") radius_of_earth = DEFAULT_SPHERICAL_EARTH_RADIUS # Get the lon and lat coords and axes @@ -548,7 +548,7 @@ def cosine_latitude_weights(cube): if np.any(lat.points < -np.pi / 2.0 - threshold) or np.any( lat.points > np.pi / 2.0 + threshold ): - warnings.warn( + warn_once_at_level( "Out of range latitude values will be " "clipped to the valid range.", UserWarning, @@ -663,7 +663,7 @@ def project(cube, target_proj, nx=None, ny=None): # Determine source coordinate system if lat_coord.coord_system is None: # Assume WGS84 latlon if unspecified - warnings.warn( + warn_once_at_level( "Coordinate system of latitude and longitude " "coordinates is not specified. Assuming WGS84 Geodetic." ) @@ -851,7 +851,7 @@ def project(cube, target_proj, nx=None, ny=None): new_cube.add_aux_coord(coord.copy(), cube.coord_dims(coord)) discarded_coords = coords_to_ignore.difference([lat_coord, lon_coord]) if discarded_coords: - warnings.warn( + warn_once_at_level( "Discarding coordinates that share dimensions with " "{} and {}: {}".format( lat_coord.name(), diff --git a/lib/iris/analysis/geometry.py b/lib/iris/analysis/geometry.py index b246b518d41..9d8a1817719 100644 --- a/lib/iris/analysis/geometry.py +++ b/lib/iris/analysis/geometry.py @@ -11,7 +11,7 @@ """ -import warnings +from iris.exceptions import warn_once_at_level import numpy as np from shapely.geometry import Polygon @@ -72,7 +72,7 @@ def _extract_relevant_cube_slice(cube, geometry): x_min_ix = np.where(x_bounds_lower <= x_min_geom)[0] x_min_ix = x_min_ix[np.argmax(x_bounds_lower[x_min_ix])] except ValueError: - warnings.warn( + warn_once_at_level( "The geometry exceeds the cube's x dimension at the " "lower end.", UserWarning, ) @@ -82,7 +82,7 @@ def _extract_relevant_cube_slice(cube, geometry): x_max_ix = np.where(x_bounds_upper >= x_max_geom)[0] x_max_ix = x_max_ix[np.argmin(x_bounds_upper[x_max_ix])] except ValueError: - warnings.warn( + warn_once_at_level( "The geometry exceeds the cube's x dimension at the " "upper end.", UserWarning, ) @@ -92,7 +92,7 @@ def _extract_relevant_cube_slice(cube, geometry): y_min_ix = np.where(y_bounds_lower <= y_min_geom)[0] y_min_ix = y_min_ix[np.argmax(y_bounds_lower[y_min_ix])] except ValueError: - warnings.warn( + warn_once_at_level( "The geometry exceeds the cube's y dimension at the " "lower end.", UserWarning, ) @@ -102,7 +102,7 @@ def _extract_relevant_cube_slice(cube, geometry): y_max_ix = np.where(y_bounds_upper >= y_max_geom)[0] y_max_ix = y_max_ix[np.argmin(y_bounds_upper[y_max_ix])] except ValueError: - warnings.warn( + warn_once_at_level( "The geometry exceeds the cube's y dimension at the " "upper end.", UserWarning, ) diff --git a/lib/iris/analysis/maths.py b/lib/iris/analysis/maths.py index b77c6cd80f9..4f4830fc922 100644 --- a/lib/iris/analysis/maths.py +++ b/lib/iris/analysis/maths.py @@ -12,7 +12,7 @@ import inspect import math import operator -import warnings +from iris.exceptions import warn_once_at_level import cf_units import dask.array as da @@ -986,7 +986,7 @@ def _broadcast_cube_coord_data(cube, other, operation_name, dim=None): raise iris.exceptions.CoordinateMultiDimError(other) if other.has_bounds(): - warnings.warn( + warn_once_at_level( "Using {!r} with a bounded coordinate is not well " "defined; ignoring bounds.".format(operation_name) ) diff --git a/lib/iris/aux_factory.py b/lib/iris/aux_factory.py index f49de62b3f0..9d6b97850c8 100644 --- a/lib/iris/aux_factory.py +++ b/lib/iris/aux_factory.py @@ -9,7 +9,7 @@ """ from abc import ABCMeta, abstractmethod -import warnings +from iris.exceptions import warn_once_at_level import cf_units import dask.array as da @@ -441,7 +441,7 @@ def _check_dependencies(pressure_at_top, sigma, surface_air_pressure): f"Coordinate '{coord.name()}' has bounds. These will " "be disregarded" ) - warnings.warn(msg, UserWarning, stacklevel=2) + warn_once_at_level(msg, UserWarning, stacklevel=2) # Check units if sigma.units.is_unknown(): @@ -520,7 +520,7 @@ def make_coord(self, coord_dims_func): if sigma.shape[-1:] not in ok_bound_shapes: raise ValueError("Invalid sigma coordinate bounds") if pressure_at_top.shape[-1:] not in [(), (1,)]: - warnings.warn( + warn_once_at_level( "Pressure at top coordinate has bounds. These are being " "disregarded" ) @@ -528,7 +528,7 @@ def make_coord(self, coord_dims_func): bds_shape = list(pressure_at_top_pts.shape) + [1] pressure_at_top = pressure_at_top_pts.reshape(bds_shape) if surface_air_pressure.shape[-1:] not in [(), (1,)]: - warnings.warn( + warn_once_at_level( "Surface pressure coordinate has bounds. These are being " "disregarded" ) @@ -595,7 +595,7 @@ def __init__(self, delta=None, sigma=None, orography=None): "Orography coordinate {!r} has bounds." " These will be disregarded.".format(orography.name()) ) - warnings.warn(msg, UserWarning, stacklevel=2) + warn_once_at_level(msg, UserWarning, stacklevel=2) self.delta = delta self.sigma = sigma @@ -681,7 +681,7 @@ def make_coord(self, coord_dims_func): if sigma.shape[-1:] not in ok_bound_shapes: raise ValueError("Invalid sigma coordinate bounds.") if orography.shape[-1:] not in [(), (1,)]: - warnings.warn( + warn_once_at_level( "Orography coordinate has bounds. " "These are being disregarded.", UserWarning, @@ -739,7 +739,7 @@ def update(self, old_coord, new_coord=None): "Orography coordinate {!r} has bounds." " These will be disregarded.".format(new_coord.name()) ) - warnings.warn(msg, UserWarning, stacklevel=2) + warn_once_at_level(msg, UserWarning, stacklevel=2) self.orography = new_coord @@ -806,7 +806,7 @@ def _check_dependencies(delta, sigma, surface_air_pressure): "Surface pressure coordinate {!r} has bounds. These will" " be disregarded.".format(surface_air_pressure.name()) ) - warnings.warn(msg, UserWarning, stacklevel=2) + warn_once_at_level(msg, UserWarning, stacklevel=2) # Check units. if sigma is not None and sigma.units.is_unknown(): @@ -896,7 +896,7 @@ def make_coord(self, coord_dims_func): if sigma.shape[-1:] not in ok_bound_shapes: raise ValueError("Invalid sigma coordinate bounds.") if surface_air_pressure.shape[-1:] not in [(), (1,)]: - warnings.warn( + warn_once_at_level( "Surface pressure coordinate has bounds. " "These are being disregarded." ) @@ -1012,7 +1012,7 @@ def _check_dependencies(sigma, eta, depth, depth_c, nsigma, zlev): "The {} coordinate {!r} has bounds. " "These are being disregarded.".format(term, coord.name()) ) - warnings.warn(msg, UserWarning, stacklevel=2) + warn_once_at_level(msg, UserWarning, stacklevel=2) for coord, term in ((depth_c, "depth_c"), (nsigma, "nsigma")): if coord is not None and coord.shape != (1,): @@ -1187,7 +1187,7 @@ def make_coord(self, coord_dims_func): "The {} coordinate {!r} has bounds. " "These are being disregarded.".format(key, name) ) - warnings.warn(msg, UserWarning, stacklevel=2) + warn_once_at_level(msg, UserWarning, stacklevel=2) # Swap bounds with points. bds_shape = list(nd_points_by_key[key].shape) + [1] bounds = nd_points_by_key[key].reshape(bds_shape) @@ -1268,7 +1268,7 @@ def _check_dependencies(sigma, eta, depth): "The {} coordinate {!r} has bounds. " "These are being disregarded.".format(term, coord.name()) ) - warnings.warn(msg, UserWarning, stacklevel=2) + warn_once_at_level(msg, UserWarning, stacklevel=2) # Check units. if sigma is not None and sigma.units.is_unknown(): @@ -1349,7 +1349,7 @@ def make_coord(self, coord_dims_func): "The {} coordinate {!r} has bounds. " "These are being disregarded.".format(key, name) ) - warnings.warn(msg, UserWarning, stacklevel=2) + warn_once_at_level(msg, UserWarning, stacklevel=2) # Swap bounds with points. bds_shape = list(nd_points_by_key[key].shape) + [1] bounds = nd_points_by_key[key].reshape(bds_shape) @@ -1444,7 +1444,7 @@ def _check_dependencies(s, c, eta, depth, depth_c): "The {} coordinate {!r} has bounds. " "These are being disregarded.".format(term, coord.name()) ) - warnings.warn(msg, UserWarning, stacklevel=2) + warn_once_at_level(msg, UserWarning, stacklevel=2) if depth_c is not None and depth_c.shape != (1,): msg = ( @@ -1543,7 +1543,7 @@ def make_coord(self, coord_dims_func): "The {} coordinate {!r} has bounds. " "These are being disregarded.".format(key, name) ) - warnings.warn(msg, UserWarning, stacklevel=2) + warn_once_at_level(msg, UserWarning, stacklevel=2) # Swap bounds with points. bds_shape = list(nd_points_by_key[key].shape) + [1] bounds = nd_points_by_key[key].reshape(bds_shape) @@ -1637,7 +1637,7 @@ def _check_dependencies(s, eta, depth, a, b, depth_c): "The {} coordinate {!r} has bounds. " "These are being disregarded.".format(term, coord.name()) ) - warnings.warn(msg, UserWarning, stacklevel=2) + warn_once_at_level(msg, UserWarning, stacklevel=2) coords = ((a, "a"), (b, "b"), (depth_c, "depth_c")) for coord, term in coords: @@ -1740,7 +1740,7 @@ def make_coord(self, coord_dims_func): "The {} coordinate {!r} has bounds. " "These are being disregarded.".format(key, name) ) - warnings.warn(msg, UserWarning, stacklevel=2) + warn_once_at_level(msg, UserWarning, stacklevel=2) # Swap bounds with points. bds_shape = list(nd_points_by_key[key].shape) + [1] bounds = nd_points_by_key[key].reshape(bds_shape) @@ -1839,7 +1839,7 @@ def _check_dependencies(s, c, eta, depth, depth_c): "The {} coordinate {!r} has bounds. " "These are being disregarded.".format(term, coord.name()) ) - warnings.warn(msg, UserWarning, stacklevel=2) + warn_once_at_level(msg, UserWarning, stacklevel=2) if depth_c is not None and depth_c.shape != (1,): msg = ( @@ -1938,7 +1938,7 @@ def make_coord(self, coord_dims_func): "The {} coordinate {!r} has bounds. " "These are being disregarded.".format(key, name) ) - warnings.warn(msg, UserWarning, stacklevel=2) + warn_once_at_level(msg, UserWarning, stacklevel=2) # Swap bounds with points. bds_shape = list(nd_points_by_key[key].shape) + [1] bounds = nd_points_by_key[key].reshape(bds_shape) diff --git a/lib/iris/config.py b/lib/iris/config.py index 79d141e53f3..25441dfb872 100644 --- a/lib/iris/config.py +++ b/lib/iris/config.py @@ -34,7 +34,7 @@ import contextlib import logging import os.path -import warnings +from iris.exceptions import warn_once_at_level def get_logger( @@ -145,7 +145,7 @@ def get_dir_option(section, option, default=None): "Ignoring config item {!r}:{!r} (section:option) as {!r}" " is not a valid directory path." ) - warnings.warn(msg.format(section, option, c_path)) + warn_once_at_level(msg.format(section, option, c_path)) return path @@ -251,7 +251,7 @@ def __setattr__(self, name, value): "Attempting to set invalid value {!r} for " "attribute {!r}. Defaulting to {!r}." ) - warnings.warn(wmsg.format(value, name, good_value)) + warn_once_at_level(wmsg.format(value, name, good_value)) value = good_value self.__dict__[name] = value diff --git a/lib/iris/coord_systems.py b/lib/iris/coord_systems.py index edf0c1871ba..de099914b7e 100644 --- a/lib/iris/coord_systems.py +++ b/lib/iris/coord_systems.py @@ -10,7 +10,7 @@ from abc import ABCMeta, abstractmethod from functools import cached_property -import warnings +from iris.exceptions import warn_once_at_level import cartopy.crs as ccrs import numpy as np @@ -449,7 +449,7 @@ def inverse_flattening(self, value): "the GeogCS object. To change other properties set them explicitly" " or create a new GeogCS instance." ) - warnings.warn(wmsg, UserWarning) + warn_once_at_level(wmsg, UserWarning) value = float(value) self._inverse_flattening = value @@ -816,7 +816,7 @@ def __repr__(self): def as_cartopy_crs(self): globe = self._ellipsoid_to_globe(self.ellipsoid, ccrs.Globe()) - warnings.warn( + warn_once_at_level( "Discarding false_easting and false_northing that are " "not used by Cartopy." ) diff --git a/lib/iris/coords.py b/lib/iris/coords.py index 1a6e8d4e6a8..d160770cd04 100644 --- a/lib/iris/coords.py +++ b/lib/iris/coords.py @@ -15,7 +15,7 @@ from functools import lru_cache from itertools import zip_longest import operator -import warnings +from iris.exceptions import warn_once_at_level import zlib import dask.array as da @@ -2055,7 +2055,7 @@ def contiguous_bounds(self): """ if not self.has_bounds(): if self.ndim == 1: - warnings.warn( + warn_once_at_level( "Coordinate {!r} is not bounded, guessing " "contiguous bounds.".format(self.name()) ) @@ -2224,7 +2224,7 @@ def serialize(x): "Collapsing a multi-dimensional coordinate. " "Metadata may not be fully descriptive for {!r}." ) - warnings.warn(msg.format(self.name())) + warn_once_at_level(msg.format(self.name())) else: try: self._sanity_check_bounds() @@ -2234,7 +2234,7 @@ def serialize(x): "Metadata may not be fully descriptive for {!r}. " "Ignoring bounds." ) - warnings.warn(msg.format(str(exc), self.name())) + warn_once_at_level(msg.format(str(exc), self.name())) self.bounds = None else: if not self.is_contiguous(): @@ -2242,7 +2242,7 @@ def serialize(x): "Collapsing a non-contiguous coordinate. " "Metadata may not be fully descriptive for {!r}." ) - warnings.warn(msg.format(self.name())) + warn_once_at_level(msg.format(self.name())) if self.has_bounds(): item = self.core_bounds() diff --git a/lib/iris/cube.py b/lib/iris/cube.py index aec80dce47e..77e7a4e13bc 100644 --- a/lib/iris/cube.py +++ b/lib/iris/cube.py @@ -15,7 +15,7 @@ from copy import deepcopy from functools import partial, reduce import operator -import warnings +from iris.exceptions import warn_once_at_level from xml.dom.minidom import Document import zlib @@ -3857,7 +3857,7 @@ def collapsed(self, coords, aggregator, **kwargs): ] if lat_match: for coord in lat_match: - warnings.warn(msg.format(coord.name())) + warn_once_at_level(msg.format(coord.name())) # Determine the dimensions we need to collapse (and those we don't) if aggregator.cell_method == "peak": @@ -4442,7 +4442,7 @@ def rolling_window(self, coord, aggregator, window, **kwargs): # now update all of the coordinates to reflect the aggregation for coord_ in self.coords(dimensions=dimension): if coord_.has_bounds(): - warnings.warn( + warn_once_at_level( "The bounds of coordinate %r were ignored in " "the rolling window operation." % coord_.name() ) diff --git a/lib/iris/exceptions.py b/lib/iris/exceptions.py index ca079998849..d205399e486 100644 --- a/lib/iris/exceptions.py +++ b/lib/iris/exceptions.py @@ -191,7 +191,7 @@ def warn_once(msg, type, stacklevel, frame): warnings.warn(msg, type, stacklevel=stacklevel) -def warn_once_at_level(msg, type, stacklevel): +def warn_once_at_level(msg, type=None, stacklevel=0): """ Raise a warning only if a similar one hasn't been raised from the same line for a given stack level. diff --git a/lib/iris/experimental/regrid.py b/lib/iris/experimental/regrid.py index 76c6002d2bf..12a35d5fb64 100644 --- a/lib/iris/experimental/regrid.py +++ b/lib/iris/experimental/regrid.py @@ -20,7 +20,7 @@ """ import copy import functools -import warnings +from iris.exceptions import warn_once_at_level import cartopy.crs as ccrs import numpy as np @@ -538,7 +538,7 @@ def regrid_reference_surface( "Cannot update aux_factory {!r} because of dropped" " coordinates.".format(factory.name()) ) - warnings.warn(msg) + warn_once_at_level(msg) return result def __call__(self, src_cube): diff --git a/lib/iris/experimental/ugrid/cf.py b/lib/iris/experimental/ugrid/cf.py index 86b76c7a751..7f0773dee89 100644 --- a/lib/iris/experimental/ugrid/cf.py +++ b/lib/iris/experimental/ugrid/cf.py @@ -10,7 +10,7 @@ Eventual destination: :mod:`iris.fileformats.cf`. """ -import warnings +from iris.exceptions import warn_once_at_level from ...fileformats import cf from .mesh import Connectivity @@ -65,7 +65,7 @@ def identify(cls, variables, ignore=None, target=None, warn=True): f"{nc_var_name}" ) if warn: - warnings.warn(message) + warn_once_at_level(message) else: # Restrict to non-string type i.e. not a # CFLabelVariable. @@ -80,7 +80,7 @@ def identify(cls, variables, ignore=None, target=None, warn=True): f"CF-netCDF label variable." ) if warn: - warnings.warn(message) + warn_once_at_level(message) return result @@ -136,7 +136,7 @@ def identify(cls, variables, ignore=None, target=None, warn=True): f"variable {nc_var_name}" ) if warn: - warnings.warn(message) + warn_once_at_level(message) else: # Restrict to non-string type i.e. not a # CFLabelVariable. @@ -154,7 +154,7 @@ def identify(cls, variables, ignore=None, target=None, warn=True): f"CF-netCDF label variable." ) if warn: - warnings.warn(message) + warn_once_at_level(message) return result @@ -211,7 +211,7 @@ def identify(cls, variables, ignore=None, target=None, warn=True): f"referenced by netCDF variable {nc_var_name}" ) if warn: - warnings.warn(message) + warn_once_at_level(message) else: # Restrict to non-string type i.e. not a # CFLabelVariable. @@ -226,7 +226,7 @@ def identify(cls, variables, ignore=None, target=None, warn=True): f"variable." ) if warn: - warnings.warn(message) + warn_once_at_level(message) return result diff --git a/lib/iris/experimental/ugrid/load.py b/lib/iris/experimental/ugrid/load.py index d2670ac690c..ad7bb540f27 100644 --- a/lib/iris/experimental/ugrid/load.py +++ b/lib/iris/experimental/ugrid/load.py @@ -15,7 +15,7 @@ from itertools import groupby from pathlib import Path import threading -import warnings +from iris.exceptions import warn_once_at_level from ...config import get_logger from ...coords import AuxCoord @@ -351,7 +351,7 @@ def _build_mesh(cf, mesh_var, file_path): ) if cf_role_message: cf_role_message += " Correcting to 'mesh_topology'." - warnings.warn(cf_role_message) + warn_once_at_level(cf_role_message) if hasattr(mesh_var, "volume_node_connectivity"): topology_dimension = 3 @@ -369,7 +369,7 @@ def _build_mesh(cf, mesh_var, file_path): f" : *Assuming* topology_dimension={topology_dimension}" ", consistent with the attached connectivities." ) - warnings.warn(msg) + warn_once_at_level(msg) else: quoted_topology_dimension = mesh_var.topology_dimension if quoted_topology_dimension != topology_dimension: @@ -381,7 +381,7 @@ def _build_mesh(cf, mesh_var, file_path): f"{quoted_topology_dimension}" " -- ignoring this as it is inconsistent." ) - warnings.warn(msg) + warn_once_at_level(msg) node_dimension = None edge_dimension = getattr(mesh_var, "edge_dimension", None) diff --git a/lib/iris/fileformats/_ff.py b/lib/iris/fileformats/_ff.py index 2545bc39ae2..a4fa3ecfade 100644 --- a/lib/iris/fileformats/_ff.py +++ b/lib/iris/fileformats/_ff.py @@ -9,7 +9,7 @@ """ import os -import warnings +from iris.exceptions import warn_once_at_level import numpy as np @@ -429,7 +429,7 @@ def grid(self): grid_class = self.GRID_STAGGERING_CLASS.get(self.grid_staggering) if grid_class is None: grid_class = NewDynamics - warnings.warn( + warn_once_at_level( "Staggered grid type: {} not currently interpreted, assuming " "standard C-grid".format(self.grid_staggering) ) @@ -554,7 +554,7 @@ def range_order(range1, range2, resolution): "may be incorrect, not having taken into account the " "boundary size." ) - warnings.warn(msg) + warn_once_at_level(msg) else: range2 = field_dim[0] - res_low range1 = field_dim[0] - halo_dim * res_low @@ -624,7 +624,7 @@ def _adjust_field_for_lbc(self, field): field.y = self._det_border(field.y, boundary_packing.y_halo) else: if field.bdy < 0: - warnings.warn( + warn_once_at_level( "The LBC has a bdy less than 0. No " "case has previously been seen of " "this, and the decompression may be " @@ -736,7 +736,7 @@ def _extract_field(self): else: subgrid = stash_entry.grid_code if subgrid not in HANDLED_GRIDS: - warnings.warn( + warn_once_at_level( "The stash code {} is on a grid {} " "which has not been explicitly " "handled by the fieldsfile loader." @@ -757,13 +757,13 @@ def _extract_field(self): "STASH to grid type mapping. Picking the P " "position as the cell type".format(stash) ) - warnings.warn(msg) + warn_once_at_level(msg) field.bzx, field.bdx = grid.regular_x(subgrid) field.bzy, field.bdy = grid.regular_y(subgrid) field.bplat = grid.pole_lat field.bplon = grid.pole_lon elif no_x or no_y: - warnings.warn( + warn_once_at_level( "Partially missing X or Y coordinate values." ) @@ -810,7 +810,7 @@ def _extract_field(self): "Input field skipped as PPField creation failed :" " error = {!r}" ) - warnings.warn(msg.format(str(valerr))) + warn_once_at_level(msg.format(str(valerr))) def __iter__(self): return pp._interpret_fields(self._extract_field()) diff --git a/lib/iris/fileformats/_nc_load_rules/actions.py b/lib/iris/fileformats/_nc_load_rules/actions.py index 09237d3f118..139b8aa5dd1 100644 --- a/lib/iris/fileformats/_nc_load_rules/actions.py +++ b/lib/iris/fileformats/_nc_load_rules/actions.py @@ -41,7 +41,7 @@ """ from functools import wraps -import warnings +from iris.exceptions import warn_once_at_level from iris.config import get_logger import iris.fileformats.cf @@ -471,7 +471,7 @@ def action_formula_type(engine, formula_root_fact): succeed = False rule_name += f"(FAILED - unrecognised formula type = {formula_type!r})" msg = f"Ignored formula of unrecognised type: {formula_type!r}." - warnings.warn(msg) + warn_once_at_level(msg) if succeed: # Check we don't already have one. existing_type = engine.requires.get("formula_type") @@ -486,7 +486,7 @@ def action_formula_type(engine, formula_root_fact): f"Formula of type ={formula_type!r} " f"overrides another of type ={existing_type!r}.)" ) - warnings.warn(msg) + warn_once_at_level(msg) rule_name += f"_{formula_type}" # Set 'requires' info for iris.fileformats.netcdf._load_aux_factory. engine.requires["formula_type"] = formula_type diff --git a/lib/iris/fileformats/_nc_load_rules/helpers.py b/lib/iris/fileformats/_nc_load_rules/helpers.py index bfef1540913..2f978a4f839 100644 --- a/lib/iris/fileformats/_nc_load_rules/helpers.py +++ b/lib/iris/fileformats/_nc_load_rules/helpers.py @@ -28,6 +28,7 @@ import iris.coord_systems import iris.coords import iris.exceptions +from iris.exceptions import warn_once_at_level import iris.fileformats.cf as cf import iris.fileformats.netcdf from iris.fileformats.netcdf.loader import _get_cf_var_data @@ -256,7 +257,7 @@ def _split_cell_methods(nc_cell_methods: str) -> List[re.Match]: "Cell methods may be incorrectly parsed due to mismatched " "brackets" ) - warnings.warn(msg, UserWarning, stacklevel=2) + warn_once_at_level(msg, UserWarning, stacklevel=2) if bracket_depth > 0 and ind in name_start_inds: name_start_inds.remove(ind) @@ -275,7 +276,7 @@ def _split_cell_methods(nc_cell_methods: str) -> List[re.Match]: msg = ( f"Failed to fully parse cell method string: {nc_cell_methods}" ) - warnings.warn(msg, UserWarning, stacklevel=2) + warn_once_at_level(msg, UserWarning, stacklevel=2) continue nc_cell_methods_matches.append(nc_cell_method_match) @@ -318,7 +319,7 @@ def parse_cell_methods(nc_cell_methods): method_words = method.split() if method_words[0].lower() not in _CM_KNOWN_METHODS: msg = "NetCDF variable contains unknown cell method {!r}" - warnings.warn( + warn_once_at_level( msg.format("{}".format(method_words[0])), UnknownCellMethodWarning, ) @@ -428,7 +429,7 @@ def build_cube_metadata(engine): name = "{}".format(cf_var.cf_name) msg = warn_record.message.args[0] msg = msg.replace("variable", "variable {!r}".format(name)) - warnings.warn(message=msg, category=UnknownCellMethodWarning) + warn_once_at_level(message=msg, category=UnknownCellMethodWarning) # Set the cube global attributes. for attr_name, attr_value in cf_var.cf_group.global_attributes.items(): @@ -436,7 +437,7 @@ def build_cube_metadata(engine): cube.attributes[str(attr_name)] = attr_value except ValueError as e: msg = "Skipping global attribute {!r}: {}" - warnings.warn(msg.format(attr_name, str(e))) + warn_once_at_level(msg.format(attr_name, str(e))) ################################################################################ @@ -512,7 +513,7 @@ def build_rotated_coordinate_system(engine, cf_grid_var): cf_grid_var, CF_ATTR_GRID_NORTH_POLE_LON, 0.0 ) if north_pole_latitude is None or north_pole_longitude is None: - warnings.warn("Rotated pole position is not fully specified") + warn_once_at_level("Rotated pole position is not fully specified") north_pole_grid_lon = getattr( cf_grid_var, CF_ATTR_GRID_NORTH_POLE_GRID_LON, 0.0 @@ -859,7 +860,7 @@ def get_attr_units(cf_var, attributes): msg = "Ignoring netCDF variable {!r} invalid units {!r}".format( cf_var.cf_name, attr_units ) - warnings.warn(msg) + warn_once_at_level(msg) attributes["invalid_units"] = attr_units attr_units = UNKNOWN_UNIT_STRING @@ -946,7 +947,7 @@ def get_cf_bounds_var(cf_coord_var): climatological = True if attr_bounds is not None and attr_climatology is not None: - warnings.warn( + warn_once_at_level( "Ignoring climatology in favour of bounds attribute " "on NetCDF variable {!r}.".format(cf_coord_var.cf_name) ) @@ -1007,7 +1008,7 @@ def build_dimension_coordinate( if ma.is_masked(points_data): points_data = ma.filled(points_data) msg = "Gracefully filling {!r} dimension coordinate masked points" - warnings.warn(msg.format(str(cf_coord_var.cf_name))) + warn_once_at_level(msg.format(str(cf_coord_var.cf_name))) # Get any coordinate bounds. cf_bounds_var, climatological = get_cf_bounds_var(cf_coord_var) @@ -1017,7 +1018,7 @@ def build_dimension_coordinate( if ma.is_masked(bounds_data): bounds_data = ma.filled(bounds_data) msg = "Gracefully filling {!r} dimension coordinate masked bounds" - warnings.warn(msg.format(str(cf_coord_var.cf_name))) + warn_once_at_level(msg.format(str(cf_coord_var.cf_name))) # Handle transposed bounds where the vertex dimension is not # the last one. Test based on shape to support different # dimension names. @@ -1082,7 +1083,7 @@ def build_dimension_coordinate( "Failed to create {name!r} dimension coordinate: {error}\n" "Gracefully creating {name!r} auxiliary coordinate instead." ) - warnings.warn(msg.format(name=str(cf_coord_var.cf_name), error=e_msg)) + warn_once_at_level(msg.format(name=str(cf_coord_var.cf_name), error=e_msg)) coord = iris.coords.AuxCoord( points_data, standard_name=standard_name, @@ -1097,7 +1098,7 @@ def build_dimension_coordinate( try: cube.add_aux_coord(coord, data_dims) except iris.exceptions.CannotAddError as e_msg: - warnings.warn(coord_skipped_msg.format(error=e_msg)) + warn_once_at_level(coord_skipped_msg.format(error=e_msg)) coord_skipped = True else: # Add the dimension coordinate to the cube. @@ -1108,7 +1109,7 @@ def build_dimension_coordinate( # Scalar coords are placed in the aux_coords container. cube.add_aux_coord(coord, data_dims) except iris.exceptions.CannotAddError as e_msg: - warnings.warn(coord_skipped_msg.format(error=e_msg)) + warn_once_at_level(coord_skipped_msg.format(error=e_msg)) coord_skipped = True if not coord_skipped: @@ -1186,7 +1187,7 @@ def build_auxiliary_coordinate( cube.add_aux_coord(coord, data_dims) except iris.exceptions.CannotAddError as e_msg: msg = "{name!r} coordinate not added to Cube: {error}" - warnings.warn(msg.format(name=str(cf_coord_var.cf_name), error=e_msg)) + warn_once_at_level(msg.format(name=str(cf_coord_var.cf_name), error=e_msg)) else: # Make a list with names, stored on the engine, so we can find them all later. engine.cube_parts["coordinates"].append((coord, cf_coord_var.cf_name)) @@ -1237,7 +1238,7 @@ def build_cell_measures(engine, cf_cm_var): cube.add_cell_measure(cell_measure, data_dims) except iris.exceptions.CannotAddError as e_msg: msg = "{name!r} cell measure not added to Cube: {error}" - warnings.warn(msg.format(name=str(cf_cm_var.cf_name), error=e_msg)) + warn_once_at_level(msg.format(name=str(cf_cm_var.cf_name), error=e_msg)) else: # Make a list with names, stored on the engine, so we can find them all later. engine.cube_parts["cell_measures"].append( @@ -1286,7 +1287,7 @@ def build_ancil_var(engine, cf_av_var): cube.add_ancillary_variable(av, data_dims) except iris.exceptions.CannotAddError as e_msg: msg = "{name!r} ancillary variable not added to Cube: {error}" - warnings.warn(msg.format(name=str(cf_av_var.cf_name), error=e_msg)) + warn_once_at_level(msg.format(name=str(cf_av_var.cf_name), error=e_msg)) else: # Make a list with names, stored on the engine, so we can find them all later. engine.cube_parts["ancillary_variables"].append( @@ -1501,7 +1502,7 @@ def has_supported_mercator_parameters(engine, cf_name): scale_factor_at_projection_origin is not None and standard_parallel is not None ): - warnings.warn( + warn_once_at_level( "It does not make sense to provide both " '"scale_factor_at_projection_origin" and "standard_parallel".' ) @@ -1533,21 +1534,21 @@ def has_supported_polar_stereographic_parameters(engine, cf_name): latitude_of_projection_origin != 90 and latitude_of_projection_origin != -90 ): - warnings.warn('"latitude_of_projection_origin" must be +90 or -90.') + warn_once_at_level('"latitude_of_projection_origin" must be +90 or -90.') is_valid = False if ( scale_factor_at_projection_origin is not None and standard_parallel is not None ): - warnings.warn( + warn_once_at_level( "It does not make sense to provide both " '"scale_factor_at_projection_origin" and "standard_parallel".' ) is_valid = False if scale_factor_at_projection_origin is None and standard_parallel is None: - warnings.warn( + warn_once_at_level( 'One of "scale_factor_at_projection_origin" and ' '"standard_parallel" is required.' ) diff --git a/lib/iris/fileformats/cf.py b/lib/iris/fileformats/cf.py index 2ed01846bd4..6d671bc7b6b 100644 --- a/lib/iris/fileformats/cf.py +++ b/lib/iris/fileformats/cf.py @@ -18,7 +18,7 @@ from collections.abc import Iterable, MutableMapping import os import re -import warnings +from iris.exceptions import warn_once_at_level import numpy as np import numpy.ma as ma @@ -280,7 +280,7 @@ def identify(cls, variables, ignore=None, target=None, warn=True): if name not in variables: if warn: message = "Missing CF-netCDF ancillary data variable %r, referenced by netCDF variable %r" - warnings.warn(message % (name, nc_var_name)) + warn_once_at_level(message % (name, nc_var_name)) else: result[name] = CFAncillaryDataVariable( name, variables[name] @@ -323,7 +323,7 @@ def identify(cls, variables, ignore=None, target=None, warn=True): if name not in variables: if warn: message = "Missing CF-netCDF auxiliary coordinate variable %r, referenced by netCDF variable %r" - warnings.warn(message % (name, nc_var_name)) + warn_once_at_level(message % (name, nc_var_name)) else: # Restrict to non-string type i.e. not a CFLabelVariable. if not _is_str_dtype(variables[name]): @@ -369,7 +369,7 @@ def identify(cls, variables, ignore=None, target=None, warn=True): if name not in variables: if warn: message = "Missing CF-netCDF boundary variable %r, referenced by netCDF variable %r" - warnings.warn(message % (name, nc_var_name)) + warn_once_at_level(message % (name, nc_var_name)) else: result[name] = CFBoundaryVariable( name, variables[name] @@ -441,7 +441,7 @@ def identify(cls, variables, ignore=None, target=None, warn=True): if name not in variables: if warn: message = "Missing CF-netCDF climatology variable %r, referenced by netCDF variable %r" - warnings.warn(message % (name, nc_var_name)) + warn_once_at_level(message % (name, nc_var_name)) else: result[name] = CFClimatologyVariable( name, variables[name] @@ -581,7 +581,7 @@ def identify(cls, variables, ignore=None, target=None, warn=True): if variable_name not in variables: if warn: message = "Missing CF-netCDF formula term variable %r, referenced by netCDF variable %r" - warnings.warn( + warn_once_at_level( message % (variable_name, nc_var_name) ) else: @@ -646,7 +646,7 @@ def identify(cls, variables, ignore=None, target=None, warn=True): if name not in variables: if warn: message = "Missing CF-netCDF grid mapping variable %r, referenced by netCDF variable %r" - warnings.warn(message % (name, nc_var_name)) + warn_once_at_level(message % (name, nc_var_name)) else: result[name] = CFGridMappingVariable( name, variables[name] @@ -685,7 +685,7 @@ def identify(cls, variables, ignore=None, target=None, warn=True): if name not in variables: if warn: message = "Missing CF-netCDF label variable %r, referenced by netCDF variable %r" - warnings.warn(message % (name, nc_var_name)) + warn_once_at_level(message % (name, nc_var_name)) else: # Register variable, but only allow string type. var = variables[name] @@ -856,7 +856,7 @@ def identify(cls, variables, ignore=None, target=None, warn=True): if variable_name not in variables: if warn: message = "Missing CF-netCDF measure variable %r, referenced by netCDF variable %r" - warnings.warn( + warn_once_at_level( message % (variable_name, nc_var_name) ) else: @@ -1067,7 +1067,7 @@ def __init__(self, file_source, warn=False, monotonic=False): "NETCDF3_CLASSIC", "NETCDF3_64BIT", ]: - warnings.warn( + warn_once_at_level( "Optimise CF-netCDF loading by converting data from NetCDF3 " 'to NetCDF4 file format using the "nccopy" command.' ) @@ -1210,7 +1210,7 @@ def _build(cf_variable): cf_variable.dimensions, ) ) - warnings.warn(msg) + warn_once_at_level(msg) # Build CF data variable relationships. if isinstance(cf_variable, CFDataVariable): @@ -1261,7 +1261,7 @@ def _build(cf_variable): cf_variable.dimensions, ) ) - warnings.warn(msg) + warn_once_at_level(msg) # Add the CF group to the variable. cf_variable.cf_group = cf_group diff --git a/lib/iris/fileformats/name_loaders.py b/lib/iris/fileformats/name_loaders.py index 0189a8806f2..1093dbfc813 100644 --- a/lib/iris/fileformats/name_loaders.py +++ b/lib/iris/fileformats/name_loaders.py @@ -9,7 +9,7 @@ import datetime from operator import itemgetter import re -import warnings +from iris.exceptions import warn_once_at_level import cf_units import numpy as np @@ -273,7 +273,7 @@ def _parse_units(units): try: units = cf_units.Unit(units) except ValueError: - warnings.warn("Unknown units: {!r}".format(units)) + warn_once_at_level("Unknown units: {!r}".format(units)) units = cf_units.Unit(None) return units @@ -611,7 +611,7 @@ def _build_cell_methods(av_or_ints, coord): else: cell_method = None msg = "Unknown {} statistic: {!r}. Unable to create cell method." - warnings.warn(msg.format(coord, av_or_int)) + warn_once_at_level(msg.format(coord, av_or_int)) cell_methods.append(cell_method) # NOTE: this can be a None return cell_methods diff --git a/lib/iris/fileformats/netcdf/loader.py b/lib/iris/fileformats/netcdf/loader.py index 20d255ea44d..27b982da265 100644 --- a/lib/iris/fileformats/netcdf/loader.py +++ b/lib/iris/fileformats/netcdf/loader.py @@ -14,7 +14,7 @@ """ from collections.abc import Iterable -import warnings +from iris.exceptions import warn_once_at_level import numpy as np @@ -350,7 +350,7 @@ def coord_from_term(term): for coord, cf_var_name in engine.cube_parts["coordinates"]: if cf_var_name == name: return coord - warnings.warn( + warn_once_at_level( "Unable to find coordinate for variable " "{!r}".format(name) ) @@ -393,7 +393,7 @@ def coord_from_term(term): coord_p0.name() ) ) - warnings.warn(msg) + warn_once_at_level(msg) coord_a = coord_from_term("a") if coord_a is not None: if coord_a.units.is_unknown(): @@ -584,7 +584,7 @@ def load_cubes(file_sources, callback=None, constraints=None): try: _load_aux_factory(engine, cube) except ValueError as e: - warnings.warn("{}".format(e)) + warn_once_at_level("{}".format(e)) # Perform any user registered callback function. cube = run_callback(callback, cube, cf_var, file_source) diff --git a/lib/iris/fileformats/netcdf/saver.py b/lib/iris/fileformats/netcdf/saver.py index c0cfd3d10b2..7234148e6eb 100644 --- a/lib/iris/fileformats/netcdf/saver.py +++ b/lib/iris/fileformats/netcdf/saver.py @@ -20,7 +20,7 @@ import re import string from typing import List -import warnings +from iris.exceptions import warn_once_at_level import cf_units import dask @@ -359,7 +359,7 @@ def _fillvalue_report(fill_info, is_masked, contains_fill_value, warn=False): ) if warn and result is not None: - warnings.warn(result) + warn_once_at_level(result) return result @@ -733,7 +733,7 @@ def write( msg = "cf_profile is available but no {} defined.".format( "cf_patch" ) - warnings.warn(msg) + warn_once_at_level(msg) @staticmethod def check_attribute_compliance(container, data_dtype): @@ -1144,7 +1144,7 @@ def _add_aux_factories(self, cube, cf_var_cube, dimension_names): "Unable to determine formula terms " "for AuxFactory: {!r}".format(factory) ) - warnings.warn(msg) + warn_once_at_level(msg) else: # Override `standard_name`, `long_name`, and `axis` of the # primary coord that signals the presence of a dimensionless @@ -2126,7 +2126,7 @@ def add_ellipsoid(ellipsoid): # osgb (a specific tmerc) elif isinstance(cs, iris.coord_systems.OSGB): - warnings.warn("OSGB coordinate system not yet handled") + warn_once_at_level("OSGB coordinate system not yet handled") # lambert azimuthal equal area elif isinstance( @@ -2192,7 +2192,7 @@ def add_ellipsoid(ellipsoid): # other else: - warnings.warn( + warn_once_at_level( "Unable to represent the horizontal " "coordinate system. The coordinate system " "type %r is not yet implemented." % type(cs) @@ -2359,7 +2359,7 @@ def set_packing_ncattrs(cfvar): "attribute, but {attr_name!r} should only be a CF " "global attribute.".format(attr_name=attr_name) ) - warnings.warn(msg) + warn_once_at_level(msg) _setncattr(cf_var, attr_name, value) @@ -2593,7 +2593,7 @@ def complete(self, issue_warnings=True) -> List[Warning]: if issue_warnings: # Issue any delayed warnings from the compute. for delayed_warning in result_warnings: - warnings.warn(delayed_warning) + warn_once_at_level(delayed_warning) return result_warnings @@ -2911,7 +2911,7 @@ def is_valid_packspec(p): msg = "cf_profile is available but no {} defined.".format( "cf_patch_conventions" ) - warnings.warn(msg) + warn_once_at_level(msg) # Add conventions attribute. sman.update_global_attributes(Conventions=conventions) diff --git a/lib/iris/fileformats/nimrod_load_rules.py b/lib/iris/fileformats/nimrod_load_rules.py index fd1ccb0e958..7b9688bbbb0 100644 --- a/lib/iris/fileformats/nimrod_load_rules.py +++ b/lib/iris/fileformats/nimrod_load_rules.py @@ -7,7 +7,7 @@ import re import string -import warnings +from iris.exceptions import warn_once_at_level import cf_units import cftime @@ -178,7 +178,7 @@ def units(cube, field): cube.units = field_units except ValueError: # Just add it as an attribute. - warnings.warn( + warn_once_at_level( "Unhandled units '{0}' recorded in cube attributes.".format( field_units ) @@ -415,7 +415,7 @@ def coord_system(field, handle_metadata_errors): field.tm_meridian_scaling, ) if any([is_missing(field, v) for v in crs_args]): - warnings.warn( + warn_once_at_level( "Coordinate Reference System is not completely defined. " "Plotting and reprojection may be impaired." ) @@ -539,7 +539,7 @@ def vertical_coord(cube, field): f"{field.vertical_coord_type} != {field.reference_vertical_coord_type}. " f"Assuming {field.vertical_coord_type}" ) - warnings.warn(msg) + warn_once_at_level(msg) coord_point = field.vertical_coord if coord_point == 8888.0: @@ -583,7 +583,7 @@ def vertical_coord(cube, field): cube.add_aux_coord(new_coord) return - warnings.warn( + warn_once_at_level( "Vertical coord {!r} not yet handled" "".format(field.vertical_coord_type), TranslationWarning, @@ -829,7 +829,7 @@ def probability_coord(cube, field, handle_metadata_errors): "standard_name", coord_keys.get("long_name", coord_keys.get("var_name", None)), ) - warnings.warn( + warn_once_at_level( f"No default units for {coord_name} coord of {cube.name()}. " "Meta-data may be incomplete." ) diff --git a/lib/iris/fileformats/pp.py b/lib/iris/fileformats/pp.py index 65e0e16d725..39aec3f307f 100644 --- a/lib/iris/fileformats/pp.py +++ b/lib/iris/fileformats/pp.py @@ -15,7 +15,7 @@ import os import re import struct -import warnings +from iris.exceptions import warn_once_at_level import cf_units import cftime @@ -1165,7 +1165,7 @@ def save(self, file_handle): "missing data. To save these as normal values, please " "set the field BMDI not equal to any valid data points." ) - warnings.warn(msg.format(mdi)) + warn_once_at_level(msg.format(mdi)) if isinstance(data, ma.MaskedArray): if ma.is_masked(data): data = data.filled(fill_value=mdi) @@ -1287,7 +1287,7 @@ def save(self, file_handle): if data.dtype == np.dtype(">f4"): lb[self.HEADER_DICT["lbuser"][0]] = 1 elif data.dtype == np.dtype(">f8"): - warnings.warn( + warn_once_at_level( "Downcasting array precision from float64 to float32" " for save.If float64 precision is required then" " please save in a different format" @@ -1729,7 +1729,7 @@ def _interpret_fields(fields): # they were encountered before the landmask reference field. if landmask_compressed_fields: if land_mask_field is None: - warnings.warn( + warn_once_at_level( "Landmask compressed fields existed without a " "landmask to decompress with. The data will have " "a shape of (0, 0) and will not read." @@ -1901,7 +1901,7 @@ def _field_gen(filename, read_data_bytes, little_ended=False): "Unable to interpret field {}. {}. Skipping " "the remainder of the file.".format(field_count, str(e)) ) - warnings.warn(msg) + warn_once_at_level(msg) break # Skip the trailing 4-byte word containing the header length @@ -1918,7 +1918,7 @@ def _field_gen(filename, read_data_bytes, little_ended=False): "after the header in the file ({} and {}). " "Skipping the remainder of the file." ) - warnings.warn( + warn_once_at_level( wmsg.format( pp_field.lblrec * PP_WORD_DEPTH, len_of_data_plus_extra ) diff --git a/lib/iris/fileformats/pp_save_rules.py b/lib/iris/fileformats/pp_save_rules.py index 0369fc9fd0f..860e0e2c02f 100644 --- a/lib/iris/fileformats/pp_save_rules.py +++ b/lib/iris/fileformats/pp_save_rules.py @@ -4,7 +4,7 @@ # See COPYING and COPYING.LESSER in the root of the repository for full # licensing details. -import warnings +from iris.exceptions import warn_once_at_level import cftime @@ -890,4 +890,4 @@ def verify(cube, field): def _conditional_warning(condition, warning): if condition: - warnings.warn(warning) + warn_once_at_level(warning) diff --git a/lib/iris/fileformats/rules.py b/lib/iris/fileformats/rules.py index 707fd587576..29b8f22003a 100644 --- a/lib/iris/fileformats/rules.py +++ b/lib/iris/fileformats/rules.py @@ -9,7 +9,7 @@ """ import collections -import warnings +from iris.exceptions import warn_once_at_level import cf_units @@ -46,7 +46,7 @@ def as_cube(self): # time-varying surface pressure in hybrid-presure. src_cubes = src_cubes.merge(unique=False) if len(src_cubes) > 1: - warnings.warn( + warn_once_at_level( "Multiple reference cubes for {}".format(self.name) ) src_cube = src_cubes[-1] @@ -329,7 +329,7 @@ def _make_cube(field, converter): cube.units = metadata.units except ValueError: msg = "Ignoring PP invalid units {!r}".format(metadata.units) - warnings.warn(msg) + warn_once_at_level(msg) cube.attributes["invalid_units"] = metadata.units cube.units = cf_units._UNKNOWN_UNIT_STRING @@ -350,7 +350,7 @@ def _resolve_factory_references( except _ReferenceError as e: msg = "Unable to create instance of {factory}. " + str(e) factory_name = factory.factory_class.__name__ - warnings.warn(msg.format(factory=factory_name)) + warn_once_at_level(msg.format(factory=factory_name)) else: aux_factory = factory.factory_class(*args) cube.add_aux_factory(aux_factory) diff --git a/lib/iris/iterate.py b/lib/iris/iterate.py index cf16c9cbe65..3ecf9faa489 100644 --- a/lib/iris/iterate.py +++ b/lib/iris/iterate.py @@ -10,7 +10,7 @@ from collections.abc import Iterator import itertools -import warnings +from iris.exceptions import warn_once_at_level import numpy as np @@ -161,7 +161,7 @@ def izip(*cubes, **kwargs): "step." % coord_a.name() ) if coord_a != coord_b: - warnings.warn( + warn_once_at_level( "Iterating over coordinate '%s' in step whose " "definitions match but whose values " "differ." % coord_a.name() diff --git a/lib/iris/pandas.py b/lib/iris/pandas.py index 4d6681e94e1..2a2e0c42063 100644 --- a/lib/iris/pandas.py +++ b/lib/iris/pandas.py @@ -11,7 +11,7 @@ """ import datetime from itertools import chain, combinations -import warnings +from iris.exceptions import warn_once_at_level import cf_units from cf_units import Unit @@ -446,7 +446,7 @@ def format_dimensional_metadata(dm_class_, values_, name_, dimensions_): if columns_ignored: ignored_args = ", ".join([t[2] for t in class_arg_mapping]) message = f"The input pandas_structure is a Series; ignoring arguments: {ignored_args} ." - warnings.warn(message) + warn_once_at_level(message) class_arg_mapping = [] non_data_names = [] @@ -896,7 +896,7 @@ def merge_metadata(meta_var_list): "'iris.FUTURE.pandas_ndim = True'. More info is in the " "documentation." ) - warnings.warn(message, FutureWarning) + warn_once_at_level(message, FutureWarning) # The legacy behaviour. data = cube.data diff --git a/lib/iris/plot.py b/lib/iris/plot.py index ebcb5c3bcba..112eb82bda4 100644 --- a/lib/iris/plot.py +++ b/lib/iris/plot.py @@ -13,7 +13,7 @@ import collections import datetime -import warnings +from iris.exceptions import warn_once_at_level import cartopy.crs as ccrs from cartopy.geodesic import Geodesic @@ -2023,7 +2023,7 @@ def update_animation_iris(i, cubes, vmin, vmax, coords): "use: {}." ) msg = msg.format(plot_func.__module__, supported) - warnings.warn(msg, UserWarning) + warn_once_at_level(msg, UserWarning) supported = ["contour", "contourf", "pcolor", "pcolormesh"] if plot_func.__name__ not in supported: @@ -2032,7 +2032,7 @@ def update_animation_iris(i, cubes, vmin, vmax, coords): "use: {}." ) msg = msg.format(plot_func.__name__, supported) - warnings.warn(msg, UserWarning) + warn_once_at_level(msg, UserWarning) # Determine plot range. vmin = kwargs.pop("vmin", min([cc.data.min() for cc in cubes]))