diff --git a/lib/iris/tests/unit/coords/__init__.py b/lib/iris/tests/unit/coords/__init__.py index d644965526..cf650251e0 100644 --- a/lib/iris/tests/unit/coords/__init__.py +++ b/lib/iris/tests/unit/coords/__init__.py @@ -15,9 +15,10 @@ import numpy.ma as ma from iris._lazy_data import is_lazy_data +from iris.tests import _shared_utils -def setup_test_arrays(self, shape, masked=False): +def _setup_test_arrays(self, shape, masked=False): # Create concrete and lazy coordinate points and bounds test arrays, # given a desired coord shape. # If masked=True, also add masked arrays with some or no masked data, @@ -103,38 +104,46 @@ def coords_all_dtypes_and_lazynesses(self, coord_class): class CoordTestMixin: - def setupTestArrays(self, shape=(3,), masked=False): - setup_test_arrays(self, shape=shape, masked=masked) + def setup_test_arrays(self, shape=(3,), masked=False): + _setup_test_arrays(self, shape=shape, masked=masked) - def assertArraysShareData(self, a1, a2, *args, **kwargs): + def assert_arrays_share_data(self, a1, a2, msg=None): # Check that two arrays are both real, same dtype, and based on the # same underlying data (so changing one will change the other). - self.assertIsRealArray(a1) - self.assertIsRealArray(a2) - self.assertEqual(a1.dtype, a2.dtype) - self.assertTrue(arrays_share_data(a1, a2), *args, **kwargs) - - def assertArraysDoNotShareData(self, a1, a2, *args, **kwargs): - self.assertFalse(arrays_share_data(a1, a2), *args, **kwargs) - - def assertIsRealArray(self, array, *args, **kwargs): + self.assert_is_real_array(a1) + self.assert_is_real_array(a2) + assert a1.dtype == a2.dtype + if not msg: + msg = f"Array {a1} should share data with {a2}" + assert arrays_share_data(a1, a2), msg + + def assert_arrays_do_not_share_data(self, a1, a2, msg=None): + if not msg: + msg = f"Array {a1} should not share data with {a2}" + assert not arrays_share_data(a1, a2), msg + + def assert_is_real_array(self, array, msg=None): # Check that the arg is a real array. - self.assertTrue(is_real_data(array), *args, **kwargs) + if not msg: + msg = f"Array {array} is not a real array" + assert is_real_data(array), msg - def assertIsLazyArray(self, array, *args, **kwargs): + def assert_is_lazy_array(self, array, msg=None): # Check that the arg is a lazy array. - self.assertTrue(is_lazy_data(array), *args, **kwargs) + if not msg: + msg = f"Array {array} is not a lazy array" + assert is_lazy_data(array), msg - def assertEqualRealArraysAndDtypes(self, a1, a2, *args, **kwargs): + def assert_equal_real_arrays_and_dtypes(self, a1, a2): # Check that two arrays are real, equal, and have same dtype. - self.assertIsRealArray(a1) - self.assertIsRealArray(a2) - self.assertEqual(a1.dtype, a2.dtype) - self.assertArrayEqual(a1, a2) + self.assert_is_real_array(a1) + self.assert_is_real_array(a2) + assert a1.dtype == a2.dtype + _shared_utils.assert_array_equal(a1, a2) - def assertEqualLazyArraysAndDtypes(self, a1, a2, *args, **kwargs): + def assert_equal_lazy_arrays_and_dtypes(self, a1, a2): # Check that two arrays are lazy, equal, and have same dtype. - self.assertIsLazyArray(a1) - self.assertIsLazyArray(a2) - self.assertEqual(a1.dtype, a2.dtype) - self.assertArrayEqual(a1.compute(), a2.compute()) + self.assert_is_lazy_array(a1) + self.assert_is_lazy_array(a2) + assert a1.dtype == a2.dtype + _shared_utils.assert_array_equal(a1.compute(), a2.compute()) diff --git a/lib/iris/tests/unit/coords/test_AncillaryVariable.py b/lib/iris/tests/unit/coords/test_AncillaryVariable.py index c0aba2b4a1..2debe4ce31 100644 --- a/lib/iris/tests/unit/coords/test_AncillaryVariable.py +++ b/lib/iris/tests/unit/coords/test_AncillaryVariable.py @@ -4,20 +4,16 @@ # See LICENSE in the root of the repository for full licensing details. """Unit tests for the :class:`iris.coords.AncillaryVariable` class.""" -# Import iris.tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests # isort:skip - -from unittest import mock - from cf_units import Unit import dask.array as da import numpy as np import numpy.ma as ma +import pytest from iris._lazy_data import as_lazy_data from iris.coords import AncillaryVariable from iris.cube import Cube +from iris.tests import _shared_utils from iris.tests.unit.coords import CoordTestMixin, lazyness_string @@ -38,7 +34,7 @@ def data_all_dtypes_and_lazynesses(self): class AncillaryVariableTestMixin(CoordTestMixin): # Define a 2-D default array shape. - def setupTestArrays(self, shape=(2, 3), masked=False): + def setup_test_arrays(self, shape=(2, 3), masked=False): # Create concrete and lazy data test arrays, given a desired shape. # If masked=True, also add masked arrays with some or no masked data. n_vals = np.prod(shape) @@ -59,10 +55,11 @@ def setupTestArrays(self, shape=(2, 3), masked=False): self.masked_data_lazy = da.from_array(mvalues, mvalues.shape, asarray=False) -class Test__init__(tests.IrisTest, AncillaryVariableTestMixin): +class Test__init__(AncillaryVariableTestMixin): # Test for AncillaryVariable creation, with real / lazy data - def setUp(self): - self.setupTestArrays(masked=True) + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays(masked=True) def test_lazyness_and_dtype_combinations(self): for ancill_var, data_lazyness in data_all_dtypes_and_lazynesses( @@ -73,76 +70,75 @@ def test_lazyness_and_dtype_combinations(self): if data_lazyness == "real": # Real data. if ancill_var.dtype == self.data_real.dtype: - self.assertArraysShareData( + self.assert_arrays_share_data( data, self.data_real, "Data values are not the same data as the provided array.", ) - self.assertIsNot( - data, - self.data_real, - "Data array is the same instance as the provided array.", + assert data is not self.data_real, ( + "Data array is the same instance as the provided array." ) else: # the original data values were cast to a test dtype. check_data = self.data_real.astype(ancill_var.dtype) - self.assertEqualRealArraysAndDtypes(data, check_data) + self.assert_equal_real_arrays_and_dtypes(data, check_data) else: # Lazy data : the core data may be promoted to float. check_data = self.data_lazy.astype(data.dtype) - self.assertEqualLazyArraysAndDtypes(data, check_data) + self.assert_equal_lazy_arrays_and_dtypes(data, check_data) # The realisation type should be correct, though. target_dtype = ancill_var.dtype - self.assertEqual(ancill_var.data.dtype, target_dtype) + assert ancill_var.data.dtype == target_dtype def test_no_masked_data_real(self): data = self.no_masked_data_real - self.assertTrue(ma.isMaskedArray(data)) - self.assertEqual(ma.count_masked(data), 0) + assert ma.isMaskedArray(data) + assert ma.count_masked(data) == 0 ancill_var = AncillaryVariable(data) - self.assertFalse(ancill_var.has_lazy_data()) - self.assertTrue(ma.isMaskedArray(ancill_var.data)) - self.assertEqual(ma.count_masked(ancill_var.data), 0) + assert not ancill_var.has_lazy_data() + assert ma.isMaskedArray(ancill_var.data) + assert ma.count_masked(ancill_var.data) == 0 def test_no_masked_data_lazy(self): data = self.no_masked_data_lazy computed = data.compute() - self.assertTrue(ma.isMaskedArray(computed)) - self.assertEqual(ma.count_masked(computed), 0) + assert ma.isMaskedArray(computed) + assert ma.count_masked(computed) == 0 ancill_var = AncillaryVariable(data) - self.assertTrue(ancill_var.has_lazy_data()) - self.assertTrue(ma.isMaskedArray(ancill_var.data)) - self.assertEqual(ma.count_masked(ancill_var.data), 0) + assert ancill_var.has_lazy_data() + assert ma.isMaskedArray(ancill_var.data) + assert ma.count_masked(ancill_var.data) == 0 def test_masked_data_real(self): data = self.masked_data_real - self.assertTrue(ma.isMaskedArray(data)) - self.assertTrue(ma.count_masked(data)) + assert ma.isMaskedArray(data) + assert ma.count_masked(data) ancill_var = AncillaryVariable(data) - self.assertFalse(ancill_var.has_lazy_data()) - self.assertTrue(ma.isMaskedArray(ancill_var.data)) - self.assertTrue(ma.count_masked(ancill_var.data)) + assert not ancill_var.has_lazy_data() + assert ma.isMaskedArray(ancill_var.data) + assert ma.count_masked(ancill_var.data) def test_masked_data_lazy(self): data = self.masked_data_lazy computed = data.compute() - self.assertTrue(ma.isMaskedArray(computed)) - self.assertTrue(ma.count_masked(computed)) + assert ma.isMaskedArray(computed) + assert ma.count_masked(computed) ancill_var = AncillaryVariable(data) - self.assertTrue(ancill_var.has_lazy_data()) - self.assertTrue(ma.isMaskedArray(ancill_var.data)) - self.assertTrue(ma.count_masked(ancill_var.data)) + assert ancill_var.has_lazy_data() + assert ma.isMaskedArray(ancill_var.data) + assert ma.count_masked(ancill_var.data) -class Test_core_data(tests.IrisTest, AncillaryVariableTestMixin): +class Test_core_data(AncillaryVariableTestMixin): # Test for AncillaryVariable.core_data() with various lazy/real data. - def setUp(self): - self.setupTestArrays() + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_real_data(self): ancill_var = AncillaryVariable(self.data_real) result = ancill_var.core_data() - self.assertArraysShareData( + self.assert_arrays_share_data( result, self.data_real, "core_data() do not share data with the internal array.", @@ -151,69 +147,72 @@ def test_real_data(self): def test_lazy_data(self): ancill_var = AncillaryVariable(self.data_lazy) result = ancill_var.core_data() - self.assertEqualLazyArraysAndDtypes(result, self.data_lazy) + self.assert_equal_lazy_arrays_and_dtypes(result, self.data_lazy) def test_lazy_points_realise(self): ancill_var = AncillaryVariable(self.data_lazy) real_data = ancill_var.data result = ancill_var.core_data() - self.assertEqualRealArraysAndDtypes(result, real_data) + self.assert_equal_real_arrays_and_dtypes(result, real_data) -class Test_lazy_data(tests.IrisTest, AncillaryVariableTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_lazy_data(AncillaryVariableTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_real_core(self): ancill_var = AncillaryVariable(self.data_real) result = ancill_var.lazy_data() - self.assertEqualLazyArraysAndDtypes(result, self.data_lazy) + self.assert_equal_lazy_arrays_and_dtypes(result, self.data_lazy) def test_lazy_core(self): ancill_var = AncillaryVariable(self.data_lazy) result = ancill_var.lazy_data() - self.assertIs(result, self.data_lazy) + assert result is self.data_lazy -class Test_has_lazy_data(tests.IrisTest, AncillaryVariableTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_has_lazy_data(AncillaryVariableTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_real_core(self): ancill_var = AncillaryVariable(self.data_real) result = ancill_var.has_lazy_data() - self.assertFalse(result) + assert not result def test_lazy_core(self): ancill_var = AncillaryVariable(self.data_lazy) result = ancill_var.has_lazy_data() - self.assertTrue(result) + assert result def test_lazy_core_realise(self): ancill_var = AncillaryVariable(self.data_lazy) ancill_var.data result = ancill_var.has_lazy_data() - self.assertFalse(result) + assert not result -class Test__getitem__(tests.IrisTest, AncillaryVariableTestMixin): +class Test__getitem__(AncillaryVariableTestMixin): # Test for AncillaryVariable indexing with various types of data. - def setUp(self): - self.setupTestArrays() + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_partial_slice_data_copy(self): parent_ancill_var = AncillaryVariable([1.0, 2.0, 3.0]) sub_ancill_var = parent_ancill_var[:1] values_before_change = sub_ancill_var.data.copy() parent_ancill_var.data[:] = -999.9 - self.assertArrayEqual(sub_ancill_var.data, values_before_change) + _shared_utils.assert_array_equal(sub_ancill_var.data, values_before_change) def test_full_slice_data_copy(self): parent_ancill_var = AncillaryVariable([1.0, 2.0, 3.0]) sub_ancill_var = parent_ancill_var[:] values_before_change = sub_ancill_var.data.copy() parent_ancill_var.data[:] = -999.9 - self.assertArrayEqual(sub_ancill_var.data, values_before_change) + _shared_utils.assert_array_equal(sub_ancill_var.data, values_before_change) def test_dtypes(self): # Index ancillary variables with real+lazy data, and either an int or @@ -230,10 +229,8 @@ def test_dtypes(self): ) sub_data = sub_ancill_var.core_data() - self.assertEqual( - sub_data.dtype, - ancill_var_dtype, - msg.format(ancill_var_dtype, data_lazyness, "data", sub_data.dtype), + assert sub_data.dtype == ancill_var_dtype, msg.format( + ancill_var_dtype, data_lazyness, "data", sub_data.dtype ) def test_lazyness(self): @@ -249,16 +246,12 @@ def test_lazyness(self): ) ancill_var_dtype = main_ancill_var.dtype sub_data_lazyness = lazyness_string(sub_ancill_var.core_data()) - self.assertEqual( - sub_data_lazyness, + assert sub_data_lazyness == data_lazyness, msg.format( + ancill_var_dtype, data_lazyness, - msg.format( - ancill_var_dtype, - data_lazyness, - "data", - data_lazyness, - sub_data_lazyness, - ), + "data", + data_lazyness, + sub_data_lazyness, ) def test_real_data_copies(self): @@ -275,18 +268,19 @@ def test_real_data_copies(self): main_data = main_ancill_var.core_data() sub_data = sub_ancill_var.core_data() sub_main_data = main_data[:2, 1] - self.assertEqualRealArraysAndDtypes(sub_data, sub_main_data) - self.assertArraysDoNotShareData( + self.assert_equal_real_arrays_and_dtypes(sub_data, sub_main_data) + self.assert_arrays_do_not_share_data( sub_data, sub_main_data, msg.format(data_lazyness, "points"), ) -class Test_copy(tests.IrisTest, AncillaryVariableTestMixin): +class Test_copy(AncillaryVariableTestMixin): # Test for AncillaryVariable.copy() with various types of data. - def setUp(self): - self.setupTestArrays() + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_lazyness(self): # Copy ancillary variables with real+lazy data, and either an int or @@ -302,16 +296,12 @@ def test_lazyness(self): ) copied_data_lazyness = lazyness_string(copied_ancill_var.core_data()) - self.assertEqual( - copied_data_lazyness, + assert copied_data_lazyness == data_lazyness, msg.format( + ancill_var_dtype, data_lazyness, - msg.format( - ancill_var_dtype, - data_lazyness, - "points", - data_lazyness, - copied_data_lazyness, - ), + "points", + data_lazyness, + copied_data_lazyness, ) def test_realdata_copies(self): @@ -328,15 +318,16 @@ def test_realdata_copies(self): if data_lazyness == "real": main_data = main_ancill_var.core_data() copied_data = copied_ancill_var.core_data() - self.assertEqualRealArraysAndDtypes(main_data, copied_data) - self.assertArraysDoNotShareData( + self.assert_equal_real_arrays_and_dtypes(main_data, copied_data) + self.assert_arrays_do_not_share_data( main_data, copied_data, msg.format(data_lazyness, "points") ) -class Test_data__getter(tests.IrisTest, AncillaryVariableTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_data__getter(AncillaryVariableTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_mutable_real_data(self): # Check that ancill_var.data returns a modifiable array, and changes @@ -346,13 +337,13 @@ def test_mutable_real_data(self): initial_values = data.copy() ancill_var.data[1:2] += 33.1 result = ancill_var.data - self.assertFalse(np.all(result == initial_values)) + assert not np.all(result == initial_values) def test_real_data(self): # Getting real data does not change or copy them. ancill_var = AncillaryVariable(self.data_real) result = ancill_var.data - self.assertArraysShareData( + self.assert_arrays_share_data( result, self.data_real, "Data values do not share data with the provided array.", @@ -361,15 +352,16 @@ def test_real_data(self): def test_lazy_data(self): # Getting lazy data realises them. ancill_var = AncillaryVariable(self.data_lazy) - self.assertTrue(ancill_var.has_lazy_data()) + assert ancill_var.has_lazy_data() result = ancill_var.data - self.assertFalse(ancill_var.has_lazy_data()) - self.assertEqualRealArraysAndDtypes(result, self.data_real) + assert not ancill_var.has_lazy_data() + self.assert_equal_real_arrays_and_dtypes(result, self.data_real) -class Test_data__setter(tests.IrisTest, AncillaryVariableTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_data__setter(AncillaryVariableTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_real_set_real(self): # Setting new real data does not make a copy. @@ -377,7 +369,7 @@ def test_real_set_real(self): new_data = self.data_real + 102.3 ancill_var.data = new_data result = ancill_var.core_data() - self.assertArraysShareData( + self.assert_arrays_share_data( result, new_data, "Data values do not share data with the assigned array.", @@ -387,7 +379,7 @@ def test_fail_bad_shape(self): # Setting real data requires matching shape. ancill_var = AncillaryVariable([1.0, 2.0]) msg = r"Require data with shape \(2,\), got \(3,\)" - with self.assertRaisesRegex(ValueError, msg): + with pytest.raises(ValueError, match=msg): ancill_var.data = np.array([1.0, 2.0, 3.0]) def test_real_set_lazy(self): @@ -396,10 +388,10 @@ def test_real_set_lazy(self): new_data = self.data_lazy + 102.3 ancill_var.data = new_data result = ancill_var.core_data() - self.assertEqualLazyArraysAndDtypes(result, new_data) + self.assert_equal_lazy_arrays_and_dtypes(result, new_data) -class Test__str__(tests.IrisTest): +class Test__str__: def test_non_time_values(self): ancillary_var = AncillaryVariable( np.array([2, 5, 9]), @@ -422,7 +414,7 @@ def test_non_time_values(self): " notes 'Measured from sea level'", ] ) - self.assertEqual(expected, ancillary_var.__str__()) + assert expected == ancillary_var.__str__() def test_time_values(self): ancillary_var = AncillaryVariable( @@ -445,10 +437,10 @@ def test_time_values(self): " long_name: 'time of previous valid detection'", ] ) - self.assertEqual(expected, ancillary_var.__str__()) + assert expected == ancillary_var.__str__() -class Test__repr__(tests.IrisTest): +class Test__repr__: def test_non_time_values(self): ancillary_var = AncillaryVariable( np.array([2, 5, 9]), @@ -459,7 +451,7 @@ def test_non_time_values(self): attributes={"notes": "Measured from sea level"}, ) expected = "" - self.assertEqual(expected, ancillary_var.__repr__()) + assert expected == ancillary_var.__repr__() def test_time_values(self): ancillary_var = AncillaryVariable( @@ -471,13 +463,14 @@ def test_time_values(self): "" ) - self.assertEqual(expected, ancillary_var.__repr__()) + assert expected == ancillary_var.__repr__() -class Test___binary_operator__(tests.IrisTest, AncillaryVariableTestMixin): +class Test___binary_operator__(AncillaryVariableTestMixin): # Test maths operations on on real+lazy data. - def setUp(self): - self.setupTestArrays() + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() self.real_ancill_var = AncillaryVariable(self.data_real) self.lazy_ancill_var = AncillaryVariable(self.data_lazy) @@ -491,9 +484,9 @@ def _check(self, result_ancill_var, expected_data, lazyness): # Test each operation on data = result_ancill_var.core_data() if lazyness == "real": - self.assertEqualRealArraysAndDtypes(expected_data, data) + self.assert_equal_real_arrays_and_dtypes(expected_data, data) else: - self.assertEqualLazyArraysAndDtypes(expected_data, data) + self.assert_equal_lazy_arrays_and_dtypes(expected_data, data) def test_add(self): for ancill_var, orig_data, data_lazyness in self.test_combinations: @@ -574,25 +567,26 @@ def test_negative(self): self._check(result, expected_data, data_lazyness) -class Test_has_bounds(tests.IrisTest): +class Test_has_bounds: def test(self): ancillary_var = AncillaryVariable(np.array([2, 9, 5])) - self.assertFalse(ancillary_var.has_bounds()) + assert not ancillary_var.has_bounds() -class Test_convert_units(tests.IrisTest): +class Test_convert_units: def test_preserves_lazy(self): test_data = np.array([[11.1, 12.2, 13.3], [21.4, 22.5, 23.6]]) lazy_data = as_lazy_data(test_data) ancill_var = AncillaryVariable(data=lazy_data, units="m") ancill_var.convert_units("ft") - self.assertTrue(ancill_var.has_lazy_data()) + assert ancill_var.has_lazy_data() test_data_ft = Unit("m").convert(test_data, "ft") - self.assertArrayAllClose(ancill_var.data, test_data_ft) + _shared_utils.assert_array_all_close(ancill_var.data, test_data_ft) -class Test_is_compatible(tests.IrisTest): - def setUp(self): +class Test_is_compatible: + @pytest.fixture(autouse=True) + def _setup(self): self.ancill_var = AncillaryVariable( [1.0, 8.0, 22.0], standard_name="number_of_observations", units="1" ) @@ -601,67 +595,61 @@ def setUp(self): def test_not_compatible_diff_name(self): # Different name() - not compatible self.modified_ancill_var.rename("air_temperature") - self.assertFalse(self.ancill_var.is_compatible(self.modified_ancill_var)) + assert not self.ancill_var.is_compatible(self.modified_ancill_var) def test_not_compatible_diff_units(self): # Different units- not compatible self.modified_ancill_var.units = "m" - self.assertFalse(self.ancill_var.is_compatible(self.modified_ancill_var)) + assert not self.ancill_var.is_compatible(self.modified_ancill_var) def test_not_compatible_diff_common_attrs(self): # Different common attributes - not compatible. self.ancill_var.attributes["source"] = "A" self.modified_ancill_var.attributes["source"] = "B" - self.assertFalse(self.ancill_var.is_compatible(self.modified_ancill_var)) + assert not self.ancill_var.is_compatible(self.modified_ancill_var) def test_compatible_diff_data(self): # Different data values - compatible. self.modified_ancill_var.data = [10.0, 20.0, 100.0] - self.assertTrue(self.ancill_var.is_compatible(self.modified_ancill_var)) + assert self.ancill_var.is_compatible(self.modified_ancill_var) def test_compatible_diff_var_name(self): # Different var_name (but same name()) - compatible. self.modified_ancill_var.var_name = "obs_num" - self.assertTrue(self.ancill_var.is_compatible(self.modified_ancill_var)) + assert self.ancill_var.is_compatible(self.modified_ancill_var) def test_compatible_diff_non_common_attributes(self): # Different non-common attributes - compatible. self.ancill_var.attributes["source"] = "A" self.modified_ancill_var.attributes["origin"] = "B" - self.assertTrue(self.ancill_var.is_compatible(self.modified_ancill_var)) + assert self.ancill_var.is_compatible(self.modified_ancill_var) def test_compatible_ignore_common_attribute(self): # ignore different common attributes - compatible. self.ancill_var.attributes["source"] = "A" self.modified_ancill_var.attributes["source"] = "B" - self.assertTrue( - self.ancill_var.is_compatible(self.modified_ancill_var, ignore="source") - ) + assert self.ancill_var.is_compatible(self.modified_ancill_var, ignore="source") -class TestEquality(tests.IrisTest): +class TestEquality: def test_nanpoints_eq_self(self): av1 = AncillaryVariable([1.0, np.nan, 2.0]) - self.assertEqual(av1, av1) + assert av1 == av1 def test_nanpoints_eq_copy(self): av1 = AncillaryVariable([1.0, np.nan, 2.0]) av2 = av1.copy() - self.assertEqual(av1, av2) + assert av1 == av2 -class Test_cube_dims(tests.IrisTest): - def test(self): +class Test_cube_dims: + def test_cube_dims(self, mocker): # Check that "coord.cube_dims(cube)" calls "cube.coord_dims(coord)". - mock_dims_result = mock.sentinel.AV_DIMS - mock_dims_call = mock.Mock(return_value=mock_dims_result) - mock_cube = mock.Mock(Cube, ancillary_variable_dims=mock_dims_call) + mock_dims_result = mocker.sentinel.AV_DIMS + mock_dims_call = mocker.Mock(return_value=mock_dims_result) + mock_cube = mocker.Mock(Cube, ancillary_variable_dims=mock_dims_call) test_var = AncillaryVariable([1], long_name="test_name") result = test_var.cube_dims(mock_cube) - self.assertEqual(result, mock_dims_result) - self.assertEqual(mock_dims_call.call_args_list, [mock.call(test_var)]) - - -if __name__ == "__main__": - tests.main() + assert result == mock_dims_result + assert mock_dims_call.call_args_list == [mocker.call(test_var)] diff --git a/lib/iris/tests/unit/coords/test_AuxCoord.py b/lib/iris/tests/unit/coords/test_AuxCoord.py index 49d3507880..300238b3c1 100644 --- a/lib/iris/tests/unit/coords/test_AuxCoord.py +++ b/lib/iris/tests/unit/coords/test_AuxCoord.py @@ -9,16 +9,14 @@ """ -# Import iris.tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests # isort:skip - from cf_units import Unit import numpy as np import numpy.ma as ma +import pytest from iris._lazy_data import as_lazy_data from iris.coords import AuxCoord +from iris.tests import _shared_utils from iris.tests.unit.coords import ( CoordTestMixin, coords_all_dtypes_and_lazynesses, @@ -28,15 +26,17 @@ class AuxCoordTestMixin(CoordTestMixin): # Define a 2-D default array shape. - def setupTestArrays(self, shape=(2, 3), masked=False): - super().setupTestArrays(shape, masked=masked) + def setup_test_arrays(self, shape=(2, 3), masked=False): + super().setup_test_arrays(shape, masked=masked) -class Test__init__(tests.IrisTest, AuxCoordTestMixin): +class Test__init__(AuxCoordTestMixin): # Test for AuxCoord creation, with various combinations of points and # bounds = real / lazy / None. - def setUp(self): - self.setupTestArrays(masked=True) + + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays(masked=True) def test_lazyness_and_dtype_combinations(self): for ( @@ -50,148 +50,145 @@ def test_lazyness_and_dtype_combinations(self): if points_type_name == "real": # Real points. if coord.dtype == self.pts_real.dtype: - self.assertArraysShareData( + self.assert_arrays_share_data( pts, self.pts_real, "Points are not the same data as the provided array.", ) - self.assertIsNot( - pts, - self.pts_real, - "Points array is the same instance as the provided array.", + assert pts is not self.pts_real, ( + "Points array is the same instance as the provided array." ) else: # the original points were cast to a test dtype. check_pts = self.pts_real.astype(coord.dtype) - self.assertEqualRealArraysAndDtypes(pts, check_pts) + self.assert_equal_real_arrays_and_dtypes(pts, check_pts) else: # Lazy points : the core data may be promoted to float. check_pts = self.pts_lazy.astype(pts.dtype) - self.assertEqualLazyArraysAndDtypes(pts, check_pts) + self.assert_equal_lazy_arrays_and_dtypes(pts, check_pts) # The realisation type should be correct, though. target_dtype = coord.dtype - self.assertEqual(coord.points.dtype, target_dtype) + assert coord.points.dtype == target_dtype # Check properties of bounds. if bounds_type_name == "real": # Real bounds. if coord.bounds_dtype == self.bds_real.dtype: - self.assertArraysShareData( + self.assert_arrays_share_data( bds, self.bds_real, "Bounds are not the same data as the provided array.", ) - self.assertIsNot( - pts, - self.pts_real, - "Bounds array is the same instance as the provided array.", + assert pts is not self.pts_real, ( + "Bounds array is the same instance as the provided array." ) else: # the original bounds were cast to a test dtype. check_bds = self.bds_real.astype(coord.bounds_dtype) - self.assertEqualRealArraysAndDtypes(bds, check_bds) + self.assert_equal_real_arrays_and_dtypes(bds, check_bds) elif bounds_type_name == "lazy": # Lazy points : the core data may be promoted to float. check_bds = self.bds_lazy.astype(bds.dtype) - self.assertEqualLazyArraysAndDtypes(bds, check_bds) + self.assert_equal_lazy_arrays_and_dtypes(bds, check_bds) # The realisation type should be correct, though. target_dtype = coord.bounds_dtype - self.assertEqual(coord.bounds.dtype, target_dtype) + assert coord.bounds.dtype == target_dtype def test_fail_bounds_shape_mismatch(self): bds_shape = list(self.bds_real.shape) bds_shape[0] += 1 bds_wrong = np.zeros(bds_shape) msg = "Bounds shape must be compatible with points shape" - with self.assertRaisesRegex(ValueError, msg): + with pytest.raises(ValueError, match=msg): AuxCoord(self.pts_real, bounds=bds_wrong) def test_no_masked_pts_real(self): data = self.no_masked_pts_real - self.assertTrue(ma.isMaskedArray(data)) - self.assertEqual(ma.count_masked(data), 0) + assert ma.isMaskedArray(data) + assert ma.count_masked(data) == 0 coord = AuxCoord(data) - self.assertFalse(coord.has_lazy_points()) - self.assertTrue(ma.isMaskedArray(coord.points)) - self.assertEqual(ma.count_masked(coord.points), 0) + assert not coord.has_lazy_points() + assert ma.isMaskedArray(coord.points) + assert ma.count_masked(coord.points) == 0 def test_no_masked_pts_lazy(self): data = self.no_masked_pts_lazy computed = data.compute() - self.assertTrue(ma.isMaskedArray(computed)) - self.assertEqual(ma.count_masked(computed), 0) + assert ma.isMaskedArray(computed) + assert ma.count_masked(computed) == 0 coord = AuxCoord(data) - self.assertTrue(coord.has_lazy_points()) - self.assertTrue(ma.isMaskedArray(coord.points)) - self.assertEqual(ma.count_masked(coord.points), 0) + assert coord.has_lazy_points() + assert ma.isMaskedArray(coord.points) + assert ma.count_masked(coord.points) == 0 def test_masked_pts_real(self): data = self.masked_pts_real - self.assertTrue(ma.isMaskedArray(data)) - self.assertTrue(ma.count_masked(data)) + assert ma.isMaskedArray(data) + assert ma.count_masked(data) coord = AuxCoord(data) - self.assertFalse(coord.has_lazy_points()) - self.assertTrue(ma.isMaskedArray(coord.points)) - self.assertTrue(ma.count_masked(coord.points)) + assert not coord.has_lazy_points() + assert ma.isMaskedArray(coord.points) + assert ma.count_masked(coord.points) def test_masked_pts_lazy(self): data = self.masked_pts_lazy computed = data.compute() - self.assertTrue(ma.isMaskedArray(computed)) - self.assertTrue(ma.count_masked(computed)) + assert ma.isMaskedArray(computed) + assert ma.count_masked(computed) coord = AuxCoord(data) - self.assertTrue(coord.has_lazy_points()) - self.assertTrue(ma.isMaskedArray(coord.points)) - self.assertTrue(ma.count_masked(coord.points)) + assert coord.has_lazy_points() + assert ma.isMaskedArray(coord.points) + assert ma.count_masked(coord.points) def test_no_masked_bds_real(self): data = self.no_masked_bds_real - self.assertTrue(ma.isMaskedArray(data)) - self.assertEqual(ma.count_masked(data), 0) + assert ma.isMaskedArray(data) + assert ma.count_masked(data) == 0 coord = AuxCoord(self.pts_real, bounds=data) - self.assertFalse(coord.has_lazy_bounds()) - self.assertTrue(ma.isMaskedArray(coord.bounds)) - self.assertEqual(ma.count_masked(coord.bounds), 0) + assert not coord.has_lazy_bounds() + assert ma.isMaskedArray(coord.bounds) + assert ma.count_masked(coord.bounds) == 0 def test_no_masked_bds_lazy(self): data = self.no_masked_bds_lazy computed = data.compute() - self.assertTrue(ma.isMaskedArray(computed)) - self.assertEqual(ma.count_masked(computed), 0) + assert ma.isMaskedArray(computed) + assert ma.count_masked(computed) == 0 coord = AuxCoord(self.pts_real, bounds=data) - self.assertTrue(coord.has_lazy_bounds()) - self.assertTrue(ma.isMaskedArray(coord.bounds)) - self.assertEqual(ma.count_masked(coord.bounds), 0) + assert coord.has_lazy_bounds() + assert ma.isMaskedArray(coord.bounds) + assert ma.count_masked(coord.bounds) == 0 def test_masked_bds_real(self): data = self.masked_bds_real - self.assertTrue(ma.isMaskedArray(data)) - self.assertTrue(ma.count_masked(data)) + assert ma.isMaskedArray(data) + assert ma.count_masked(data) coord = AuxCoord(self.pts_real, bounds=data) - self.assertFalse(coord.has_lazy_bounds()) - self.assertTrue(ma.isMaskedArray(coord.bounds)) - self.assertTrue(ma.count_masked(coord.bounds)) + assert not coord.has_lazy_bounds() + assert ma.isMaskedArray(coord.bounds) + assert ma.count_masked(coord.bounds) def test_masked_bds_lazy(self): data = self.masked_bds_lazy computed = data.compute() - self.assertTrue(ma.isMaskedArray(computed)) - self.assertTrue(ma.count_masked(computed)) + assert ma.isMaskedArray(computed) + assert ma.count_masked(computed) coord = AuxCoord(self.pts_real, bounds=data) - self.assertTrue(coord.has_lazy_bounds()) - self.assertTrue(ma.isMaskedArray(coord.bounds)) - self.assertTrue(ma.count_masked(coord.bounds)) + assert coord.has_lazy_bounds() + assert ma.isMaskedArray(coord.bounds) + assert ma.count_masked(coord.bounds) -class Test_core_points(tests.IrisTest, AuxCoordTestMixin): +class Test_core_points(AuxCoordTestMixin): # Test for AuxCoord.core_points() with various types of points and bounds. - def setUp(self): - self.setupTestArrays() + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_real_points(self): coord = AuxCoord(self.pts_real) result = coord.core_points() - self.assertArraysShareData( + self.assert_arrays_share_data( result, self.pts_real, "core_points() do not share data with the internal array.", @@ -200,29 +197,30 @@ def test_real_points(self): def test_lazy_points(self): coord = AuxCoord(self.pts_lazy) result = coord.core_points() - self.assertEqualLazyArraysAndDtypes(result, self.pts_lazy) + self.assert_equal_lazy_arrays_and_dtypes(result, self.pts_lazy) def test_lazy_points_realise(self): coord = AuxCoord(self.pts_lazy) real_points = coord.points result = coord.core_points() - self.assertEqualRealArraysAndDtypes(result, real_points) + self.assert_equal_real_arrays_and_dtypes(result, real_points) -class Test_core_bounds(tests.IrisTest, AuxCoordTestMixin): +class Test_core_bounds(AuxCoordTestMixin): # Test for AuxCoord.core_bounds() with various types of points and bounds. - def setUp(self): - self.setupTestArrays() + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_no_bounds(self): coord = AuxCoord(self.pts_real) result = coord.core_bounds() - self.assertIsNone(result) + assert result is None def test_real_bounds(self): coord = AuxCoord(self.pts_real, bounds=self.bds_real) result = coord.core_bounds() - self.assertArraysShareData( + self.assert_arrays_share_data( result, self.bds_real, "core_bounds() do not share data with the internal array.", @@ -231,130 +229,135 @@ def test_real_bounds(self): def test_lazy_bounds(self): coord = AuxCoord(self.pts_real, bounds=self.bds_lazy) result = coord.core_bounds() - self.assertEqualLazyArraysAndDtypes(result, self.bds_lazy) + self.assert_equal_lazy_arrays_and_dtypes(result, self.bds_lazy) def test_lazy_bounds_realise(self): coord = AuxCoord(self.pts_real, bounds=self.bds_lazy) real_bounds = coord.bounds result = coord.core_bounds() - self.assertEqualRealArraysAndDtypes(result, real_bounds) + self.assert_equal_real_arrays_and_dtypes(result, real_bounds) -class Test_lazy_points(tests.IrisTest, AuxCoordTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_lazy_points(AuxCoordTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_real_core(self): coord = AuxCoord(self.pts_real) result = coord.lazy_points() - self.assertEqualLazyArraysAndDtypes(result, self.pts_lazy) + self.assert_equal_lazy_arrays_and_dtypes(result, self.pts_lazy) def test_lazy_core(self): coord = AuxCoord(self.pts_lazy) result = coord.lazy_points() - self.assertIs(result, self.pts_lazy) + assert result is self.pts_lazy -class Test_lazy_bounds(tests.IrisTest, AuxCoordTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_lazy_bounds(AuxCoordTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_no_bounds(self): coord = AuxCoord(self.pts_real) result = coord.lazy_bounds() - self.assertIsNone(result) + assert result is None def test_real_core(self): coord = AuxCoord(self.pts_real, bounds=self.bds_real) result = coord.lazy_bounds() - self.assertEqualLazyArraysAndDtypes(result, self.bds_lazy) + self.assert_equal_lazy_arrays_and_dtypes(result, self.bds_lazy) def test_lazy_core(self): coord = AuxCoord(self.pts_real, bounds=self.bds_lazy) result = coord.lazy_bounds() - self.assertIs(result, self.bds_lazy) + assert result is self.bds_lazy -class Test_has_lazy_points(tests.IrisTest, AuxCoordTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_has_lazy_points(AuxCoordTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_real_core(self): coord = AuxCoord(self.pts_real) result = coord.has_lazy_points() - self.assertFalse(result) + assert not result def test_lazy_core(self): coord = AuxCoord(self.pts_lazy) result = coord.has_lazy_points() - self.assertTrue(result) + assert result def test_lazy_core_realise(self): coord = AuxCoord(self.pts_lazy) coord.points result = coord.has_lazy_points() - self.assertFalse(result) + assert not result -class Test_has_lazy_bounds(tests.IrisTest, AuxCoordTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_has_lazy_bounds(AuxCoordTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_real_core(self): coord = AuxCoord(self.pts_real, bounds=self.bds_real) result = coord.has_lazy_bounds() - self.assertFalse(result) + assert not result def test_lazy_core(self): coord = AuxCoord(self.pts_real, bounds=self.bds_lazy) result = coord.has_lazy_bounds() - self.assertTrue(result) + assert result def test_lazy_core_realise(self): coord = AuxCoord(self.pts_real, bounds=self.bds_lazy) coord.bounds result = coord.has_lazy_bounds() - self.assertFalse(result) + assert not result -class Test_bounds_dtype(tests.IrisTest, AuxCoordTestMixin): +class Test_bounds_dtype(AuxCoordTestMixin): def test_i16(self): test_dtype = np.int16 coord = AuxCoord([1], bounds=np.array([[0, 4]], dtype=test_dtype)) result = coord.bounds_dtype - self.assertEqual(result, test_dtype) + assert result == test_dtype def test_u16(self): test_dtype = np.uint16 coord = AuxCoord([1], bounds=np.array([[0, 4]], dtype=test_dtype)) result = coord.bounds_dtype - self.assertEqual(result, test_dtype) + assert result == test_dtype def test_f16(self): test_dtype = np.float16 coord = AuxCoord([1], bounds=np.array([[0, 4]], dtype=test_dtype)) result = coord.bounds_dtype - self.assertEqual(result, test_dtype) + assert result == test_dtype -class Test__getitem__(tests.IrisTest, AuxCoordTestMixin): +class Test__getitem__(AuxCoordTestMixin): # Test for AuxCoord indexing with various types of points and bounds. - def setUp(self): - self.setupTestArrays() + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_partial_slice_data_copy(self): parent_coord = AuxCoord([1.0, 2.0, 3.0]) sub_coord = parent_coord[:1] values_before_change = sub_coord.points.copy() parent_coord.points[:] = -999.9 - self.assertArrayEqual(sub_coord.points, values_before_change) + _shared_utils.assert_array_equal(sub_coord.points, values_before_change) def test_full_slice_data_copy(self): parent_coord = AuxCoord([1.0, 2.0, 3.0]) sub_coord = parent_coord[:] values_before_change = sub_coord.points.copy() parent_coord.points[:] = -999.9 - self.assertArrayEqual(sub_coord.points, values_before_change) + _shared_utils.assert_array_equal(sub_coord.points, values_before_change) def test_dtypes(self): # Index coords with all combinations of real+lazy points+bounds, and @@ -376,31 +379,23 @@ def test_dtypes(self): ) sub_points = sub_coord.core_points() - self.assertEqual( - sub_points.dtype, + assert sub_points.dtype == coord_dtype, msg.format( coord_dtype, - msg.format( - coord_dtype, - points_type_name, - bounds_type_name, - "points", - sub_points.dtype, - ), + points_type_name, + bounds_type_name, + "points", + sub_points.dtype, ) if bounds_type_name != "no": sub_bounds = sub_coord.core_bounds() main_bounds_dtype = main_coord.bounds_dtype - self.assertEqual( - sub_bounds.dtype, + assert sub_bounds.dtype == main_bounds_dtype, msg.format( main_bounds_dtype, - msg.format( - main_bounds_dtype, - points_type_name, - bounds_type_name, - "bounds", - sub_bounds.dtype, - ), + points_type_name, + bounds_type_name, + "bounds", + sub_bounds.dtype, ) def test_lazyness(self): @@ -421,32 +416,24 @@ def test_lazyness(self): ) coord_dtype = main_coord.dtype sub_points_lazyness = lazyness_string(sub_coord.core_points()) - self.assertEqual( - sub_points_lazyness, + assert sub_points_lazyness == points_type_name, msg.format( + coord_dtype, points_type_name, - msg.format( - coord_dtype, - points_type_name, - bounds_type_name, - "points", - points_type_name, - sub_points_lazyness, - ), + bounds_type_name, + "points", + points_type_name, + sub_points_lazyness, ) if bounds_type_name != "no": sub_bounds_lazy = lazyness_string(sub_coord.core_bounds()) - self.assertEqual( - sub_bounds_lazy, + assert sub_bounds_lazy == bounds_type_name, msg.format( + coord_dtype, + points_type_name, + bounds_type_name, + "bounds", bounds_type_name, - msg.format( - coord_dtype, - points_type_name, - bounds_type_name, - "bounds", - bounds_type_name, - sub_bounds_lazy, - ), + sub_bounds_lazy, ) def test_real_data_copies(self): @@ -467,8 +454,8 @@ def test_real_data_copies(self): main_points = main_coord.core_points() sub_points = sub_coord.core_points() sub_main_points = main_points[:2, 1] - self.assertEqualRealArraysAndDtypes(sub_points, sub_main_points) - self.assertArraysDoNotShareData( + self.assert_equal_real_arrays_and_dtypes(sub_points, sub_main_points) + self.assert_arrays_do_not_share_data( sub_points, sub_main_points, msg.format(points_lazyness, bounds_lazyness, "points"), @@ -478,18 +465,19 @@ def test_real_data_copies(self): main_bounds = main_coord.core_bounds() sub_bounds = sub_coord.core_bounds() sub_main_bounds = main_bounds[:2, 1] - self.assertEqualRealArraysAndDtypes(sub_bounds, sub_main_bounds) - self.assertArraysDoNotShareData( + self.assert_equal_real_arrays_and_dtypes(sub_bounds, sub_main_bounds) + self.assert_arrays_do_not_share_data( sub_bounds, sub_main_bounds, msg.format(points_lazyness, bounds_lazyness, "bounds"), ) -class Test_copy(tests.IrisTest, AuxCoordTestMixin): +class Test_copy(AuxCoordTestMixin): # Test for AuxCoord.copy() with various types of points and bounds. - def setUp(self): - self.setupTestArrays() + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_lazyness(self): # Copy coords with all combinations of real+lazy points+bounds, and @@ -510,32 +498,24 @@ def test_lazyness(self): ) copied_pts_lazyness = lazyness_string(copied_coord.core_points()) - self.assertEqual( - copied_pts_lazyness, + assert copied_pts_lazyness == points_lazyness, msg.format( + coord_dtype, points_lazyness, - msg.format( - coord_dtype, - points_lazyness, - bounds_lazyness, - "points", - points_lazyness, - copied_pts_lazyness, - ), + bounds_lazyness, + "points", + points_lazyness, + copied_pts_lazyness, ) if bounds_lazyness != "no": copied_bds_lazy = lazyness_string(copied_coord.core_bounds()) - self.assertEqual( - copied_bds_lazy, + assert copied_bds_lazy == bounds_lazyness, msg.format( + coord_dtype, + points_lazyness, + bounds_lazyness, + "bounds", bounds_lazyness, - msg.format( - coord_dtype, - points_lazyness, - bounds_lazyness, - "bounds", - bounds_lazyness, - copied_bds_lazy, - ), + copied_bds_lazy, ) def test_realdata_copies(self): @@ -556,8 +536,8 @@ def test_realdata_copies(self): if points_lazyness == "real": main_points = main_coord.core_points() copied_points = copied_coord.core_points() - self.assertEqualRealArraysAndDtypes(main_points, copied_points) - self.assertArraysDoNotShareData( + self.assert_equal_real_arrays_and_dtypes(main_points, copied_points) + self.assert_arrays_do_not_share_data( main_points, copied_points, msg.format(points_lazyness, bounds_lazyness, "points"), @@ -566,17 +546,18 @@ def test_realdata_copies(self): if bounds_lazyness == "real": main_bounds = main_coord.core_bounds() copied_bounds = copied_coord.core_bounds() - self.assertEqualRealArraysAndDtypes(main_bounds, copied_bounds) - self.assertArraysDoNotShareData( + self.assert_equal_real_arrays_and_dtypes(main_bounds, copied_bounds) + self.assert_arrays_do_not_share_data( main_bounds, copied_bounds, msg.format(points_lazyness, bounds_lazyness, "bounds"), ) -class Test_points__getter(tests.IrisTest, AuxCoordTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_points__getter(AuxCoordTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_mutable_real_points(self): # Check that coord.points returns a modifiable array, and changes to it @@ -586,13 +567,13 @@ def test_mutable_real_points(self): initial_values = data.copy() coord.points[1:2] += 33.1 result = coord.points - self.assertFalse(np.all(result == initial_values)) + assert not np.all(result == initial_values) def test_real_points(self): # Getting real points does not change or copy them. coord = AuxCoord(self.pts_real) result = coord.points - self.assertArraysShareData( + self.assert_arrays_share_data( result, self.pts_real, "Points do not share data with the provided array.", @@ -601,17 +582,17 @@ def test_real_points(self): def test_lazy_points(self): # Getting lazy points realises them. coord = AuxCoord(self.pts_lazy) - self.assertTrue(coord.has_lazy_points()) + assert coord.has_lazy_points() result = coord.points - self.assertFalse(coord.has_lazy_points()) - self.assertEqualRealArraysAndDtypes(result, self.pts_real) + assert not coord.has_lazy_points() + self.assert_equal_real_arrays_and_dtypes(result, self.pts_real) def test_real_points_with_real_bounds(self): # Getting real points does not change real bounds. coord = AuxCoord(self.pts_real, bounds=self.bds_real) coord.points result = coord.core_bounds() - self.assertArraysShareData( + self.assert_arrays_share_data( result, self.bds_real, "Bounds do not share data with the provided array.", @@ -621,25 +602,26 @@ def test_real_points_with_lazy_bounds(self): # Getting real points does not touch lazy bounds. coord = AuxCoord(self.pts_real, bounds=self.bds_lazy) coord.points - self.assertTrue(coord.has_lazy_bounds()) + assert coord.has_lazy_bounds() def test_lazy_points_with_real_bounds(self): # Getting lazy points does not affect real bounds. coord = AuxCoord(self.pts_lazy, bounds=self.bds_real) coord.points result = coord.core_bounds() - self.assertEqualRealArraysAndDtypes(result, self.bds_real) + self.assert_equal_real_arrays_and_dtypes(result, self.bds_real) def test_lazy_points_with_lazy_bounds(self): # Getting lazy points does not touch lazy bounds. coord = AuxCoord(self.pts_lazy, bounds=self.bds_lazy) coord.points - self.assertTrue(coord.has_lazy_bounds()) + assert coord.has_lazy_bounds() -class Test_points__setter(tests.IrisTest, AuxCoordTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_points__setter(AuxCoordTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_real_set_real(self): # Setting new real points does not make a copy. @@ -647,7 +629,7 @@ def test_real_set_real(self): new_pts = self.pts_real + 102.3 coord.points = new_pts result = coord.core_points() - self.assertArraysShareData( + self.assert_arrays_share_data( result, new_pts, "Points do not share data with the assigned array.", @@ -657,7 +639,7 @@ def test_fail_bad_shape(self): # Setting real points requires matching shape. coord = AuxCoord([1.0, 2.0]) msg = r"Require data with shape \(2,\), got \(3,\)" - with self.assertRaisesRegex(ValueError, msg): + with pytest.raises(ValueError, match=msg): coord.points = np.array([1.0, 2.0, 3.0]) def test_real_set_lazy(self): @@ -666,7 +648,7 @@ def test_real_set_lazy(self): new_pts = self.pts_lazy + 102.3 coord.points = new_pts result = coord.core_points() - self.assertEqualLazyArraysAndDtypes(result, new_pts) + self.assert_equal_lazy_arrays_and_dtypes(result, new_pts) def test_set_points_with_lazy_bounds(self): # Setting points does not touch lazy bounds. @@ -674,12 +656,13 @@ def test_set_points_with_lazy_bounds(self): new_pts = self.pts_real + 102.3 coord.points = new_pts result = coord.core_bounds() - self.assertEqualLazyArraysAndDtypes(result, self.bds_lazy) + self.assert_equal_lazy_arrays_and_dtypes(result, self.bds_lazy) -class Test_bounds__getter(tests.IrisTest, AuxCoordTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_bounds__getter(AuxCoordTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_mutable_real_bounds(self): # Check that coord.bounds returns a modifiable array, and changes to it @@ -690,13 +673,13 @@ def test_mutable_real_bounds(self): initial_values = bds_data.copy() coord.bounds[1:2] += 33.1 result = coord.bounds - self.assertFalse(np.all(result == initial_values)) + assert not np.all(result == initial_values) def test_real_bounds(self): # Getting real bounds does not change or copy them. coord = AuxCoord(self.pts_real, bounds=self.bds_real) result = coord.bounds - self.assertArraysShareData( + self.assert_arrays_share_data( result, self.bds_real, "Bounds do not share data with the provided array.", @@ -705,21 +688,22 @@ def test_real_bounds(self): def test_lazy_bounds(self): # Getting lazy bounds realises them. coord = AuxCoord(self.pts_real, bounds=self.bds_lazy) - self.assertTrue(coord.has_lazy_bounds()) + assert coord.has_lazy_bounds() result = coord.bounds - self.assertFalse(coord.has_lazy_bounds()) - self.assertEqualRealArraysAndDtypes(result, self.bds_real) + assert not coord.has_lazy_bounds() + self.assert_equal_real_arrays_and_dtypes(result, self.bds_real) def test_lazy_bounds_with_lazy_points(self): # Getting lazy bounds does not fetch the points. coord = AuxCoord(self.pts_lazy, bounds=self.bds_lazy) coord.bounds - self.assertTrue(coord.has_lazy_points()) + assert coord.has_lazy_points() -class Test_bounds__setter(tests.IrisTest, AuxCoordTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_bounds__setter(AuxCoordTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_set_real_bounds(self): # Setting new real bounds does not make a copy. @@ -727,7 +711,7 @@ def test_set_real_bounds(self): new_bounds = self.bds_real + 102.3 coord.bounds = new_bounds result = coord.core_bounds() - self.assertArraysShareData( + self.assert_arrays_share_data( result, new_bounds, "Bounds do not share data with the assigned array.", @@ -737,7 +721,7 @@ def test_fail_bad_shape(self): # Setting real points requires matching shape. coord = AuxCoord(self.pts_real, bounds=self.bds_real) msg = "must be compatible with points shape" - with self.assertRaisesRegex(ValueError, msg): + with pytest.raises(ValueError, match=msg): coord.bounds = np.array([1.0, 2.0, 3.0]) def test_set_lazy_bounds(self): @@ -746,17 +730,17 @@ def test_set_lazy_bounds(self): new_bounds = self.bds_lazy + 102.3 coord.bounds = new_bounds result = coord.core_bounds() - self.assertEqualLazyArraysAndDtypes(result, new_bounds) + self.assert_equal_lazy_arrays_and_dtypes(result, new_bounds) def test_set_bounds_with_lazy_points(self): # Setting bounds does not change lazy points. coord = AuxCoord(self.pts_lazy, bounds=self.bds_real) new_bounds = self.bds_real + 102.3 coord.bounds = new_bounds - self.assertTrue(coord.has_lazy_points()) + assert coord.has_lazy_points() -class Test_convert_units(tests.IrisTest): +class Test_convert_units: def test_preserves_lazy(self): test_bounds = np.array( [ @@ -769,28 +753,24 @@ def test_preserves_lazy(self): lazy_bounds = as_lazy_data(test_bounds) coord = AuxCoord(points=lazy_points, bounds=lazy_bounds, units="m") coord.convert_units("ft") - self.assertTrue(coord.has_lazy_points()) - self.assertTrue(coord.has_lazy_bounds()) + assert coord.has_lazy_points() + assert coord.has_lazy_bounds() test_points_ft = Unit("m").convert(test_points, "ft") test_bounds_ft = Unit("m").convert(test_bounds, "ft") - self.assertArrayAllClose(coord.points, test_points_ft) - self.assertArrayAllClose(coord.bounds, test_bounds_ft) + _shared_utils.assert_array_all_close(coord.points, test_points_ft) + _shared_utils.assert_array_all_close(coord.bounds, test_bounds_ft) -class TestEquality(tests.IrisTest): +class TestEquality: def test_nanpoints_eq_self(self): co1 = AuxCoord([1.0, np.nan, 2.0]) - self.assertEqual(co1, co1) + assert co1 == co1 def test_nanpoints_eq_copy(self): co1 = AuxCoord([1.0, np.nan, 2.0]) co2 = co1.copy() - self.assertEqual(co1, co2) + assert co1 == co2 def test_nanbounds_eq_self(self): co1 = AuxCoord([15.0, 25.0], bounds=[[14.0, 16.0], [24.0, np.nan]]) - self.assertEqual(co1, co1) - - -if __name__ == "__main__": - tests.main() + assert co1 == co1 diff --git a/lib/iris/tests/unit/coords/test_Cell.py b/lib/iris/tests/unit/coords/test_Cell.py index 2e4c5944e0..dc3ddab561 100644 --- a/lib/iris/tests/unit/coords/test_Cell.py +++ b/lib/iris/tests/unit/coords/test_Cell.py @@ -270,7 +270,7 @@ def test_cell_rhs(self): class Test_hashing: @pytest.mark.parametrize( "point", - ( + [ pytest.param(np.float32(1.0), id="float32"), pytest.param(np.float64(1.0), id="float64"), pytest.param(np.int16(1), id="int16"), @@ -282,7 +282,7 @@ class Test_hashing: pytest.param(True, id="bool"), pytest.param(np.ma.masked, id="masked"), pytest.param(datetime.datetime(2001, 1, 1), id="datetime"), - ), + ], ) def test_cell_is_hashable(self, point): """Test a Cell object is hashable with various point/bound types.""" diff --git a/lib/iris/tests/unit/coords/test_CellMeasure.py b/lib/iris/tests/unit/coords/test_CellMeasure.py index 7da4b1b48b..6c64c6e165 100644 --- a/lib/iris/tests/unit/coords/test_CellMeasure.py +++ b/lib/iris/tests/unit/coords/test_CellMeasure.py @@ -13,7 +13,7 @@ from iris.tests import _shared_utils -class Tests: +class TestCellMeasure: @pytest.fixture(autouse=True) def _setup(self): self.values = np.array((10.0, 12.0, 16.0, 9.0)) @@ -115,7 +115,7 @@ def test__eq__(self): class Test_cube_dims: - def test(self, mocker): + def test_cube_dims(self, mocker): # Check that "coord.cube_dims(cube)" calls "cube.coord_dims(coord)". mock_dims_result = mocker.sentinel.CM_DIMS mock_dims_call = mocker.Mock(return_value=mock_dims_result) diff --git a/lib/iris/tests/unit/coords/test_CellMethod.py b/lib/iris/tests/unit/coords/test_CellMethod.py index 3bb25a3947..a58eb6eac9 100644 --- a/lib/iris/tests/unit/coords/test_CellMethod.py +++ b/lib/iris/tests/unit/coords/test_CellMethod.py @@ -10,7 +10,7 @@ from iris.coords import AuxCoord, CellMethod -class Test: +class TestCellMethod: @pytest.fixture(autouse=True) def _setup(self): self.method = "mean" diff --git a/lib/iris/tests/unit/coords/test_Coord.py b/lib/iris/tests/unit/coords/test_Coord.py index ba77379a50..786b00b143 100644 --- a/lib/iris/tests/unit/coords/test_Coord.py +++ b/lib/iris/tests/unit/coords/test_Coord.py @@ -4,14 +4,8 @@ # See LICENSE in the root of the repository for full licensing details. """Unit tests for the :class:`iris.coords.Coord` class.""" -# Import iris.tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests # isort:skip - import collections from datetime import datetime -from unittest import mock -import warnings import cf_units import dask.array as da @@ -30,8 +24,9 @@ Pair = collections.namedtuple("Pair", "points bounds") -class Test_nearest_neighbour_index__ascending(tests.IrisTest): - def setUp(self): +class Test_nearest_neighbour_index__ascending: + @pytest.fixture(autouse=True) + def _setup(self): points = [0.0, 90.0, 180.0, 270.0] self.coord = DimCoord(points, circular=False, units="degrees") @@ -44,7 +39,7 @@ def _test_nearest_neighbour_index(self, target, bounds=None, circular=False): self.coord.bounds = bounds self.coord.circular = circular results = [self.coord.nearest_neighbour_index(ind) for ind in ext_pnts] - self.assertEqual(results, target) + assert results == target def test_nobounds(self): target = [0, 0, 1, 3, 3] @@ -80,11 +75,12 @@ def test_scalar(self): def test_bounded_float_point(self): coord = DimCoord(1, bounds=[0, 2]) result = coord.nearest_neighbour_index(2.5) - self.assertEqual(result, 0) + assert result == 0 -class Test_nearest_neighbour_index__descending(tests.IrisTest): - def setUp(self): +class Test_nearest_neighbour_index__descending: + @pytest.fixture(autouse=True) + def _setup(self): points = [270.0, 180.0, 90.0, 0.0] self.coord = DimCoord(points, circular=False, units="degrees") @@ -95,7 +91,7 @@ def _test_nearest_neighbour_index(self, target, bounds=False, circular=False): self.coord.bounds = _bounds self.coord.circular = circular results = [self.coord.nearest_neighbour_index(ind) for ind in ext_pnts] - self.assertEqual(results, target) + assert results == target def test_nobounds(self): target = [3, 3, 2, 0, 0] @@ -114,8 +110,9 @@ def test_bounded_circular(self): self._test_nearest_neighbour_index(target, bounds=True, circular=True) -class Test_guess_bounds(tests.IrisTest): - def setUp(self): +class Test_guess_bounds: + @pytest.fixture(autouse=True) + def _setup(self): self.coord = DimCoord( np.array([-160, -120, 0, 30, 150, 170]), units="degree", @@ -136,7 +133,7 @@ def test_non_circular(self): [160.0, 180.0], ] ) - self.assertArrayEqual(target, self.coord.bounds) + _shared_utils.assert_array_equal(target, self.coord.bounds) def test_circular_increasing(self): self.coord.guess_bounds() @@ -150,7 +147,7 @@ def test_circular_increasing(self): [160.0, 185.0], ] ) - self.assertArrayEqual(target, self.coord.bounds) + _shared_utils.assert_array_equal(target, self.coord.bounds) def test_circular_decreasing(self): self.coord.points = self.coord.points[::-1] @@ -165,7 +162,7 @@ def test_circular_decreasing(self): [-140.0, -175.0], ] ) - self.assertArrayEqual(target, self.coord.bounds) + _shared_utils.assert_array_equal(target, self.coord.bounds) def test_circular_increasing_alt_range(self): self.coord.points = np.array([10, 30, 90, 150, 210, 220]) @@ -180,7 +177,7 @@ def test_circular_increasing_alt_range(self): [215.0, 295.0], ] ) - self.assertArrayEqual(target, self.coord.bounds) + _shared_utils.assert_array_equal(target, self.coord.bounds) def test_circular_decreasing_alt_range(self): self.coord.points = np.array([10, 30, 90, 150, 210, 220])[::-1] @@ -195,49 +192,57 @@ def test_circular_decreasing_alt_range(self): [20, -65], ] ) - self.assertArrayEqual(target, self.coord.bounds) + _shared_utils.assert_array_equal(target, self.coord.bounds) -class Test_guess_bounds__default_enabled_latitude_clipping(tests.IrisTest): +class Test_guess_bounds__default_enabled_latitude_clipping: def test_all_inside(self): lat = DimCoord([-10, 0, 20], units="degree", standard_name="latitude") lat.guess_bounds() - self.assertArrayEqual(lat.bounds, [[-15, -5], [-5, 10], [10, 30]]) + _shared_utils.assert_array_equal(lat.bounds, [[-15, -5], [-5, 10], [10, 30]]) def test_points_inside_bounds_outside(self): lat = DimCoord([-80, 0, 70], units="degree", standard_name="latitude") lat.guess_bounds() - self.assertArrayEqual(lat.bounds, [[-90, -40], [-40, 35], [35, 90]]) + _shared_utils.assert_array_equal(lat.bounds, [[-90, -40], [-40, 35], [35, 90]]) def test_points_inside_bounds_outside_grid_latitude(self): lat = DimCoord([-80, 0, 70], units="degree", standard_name="grid_latitude") lat.guess_bounds() - self.assertArrayEqual(lat.bounds, [[-90, -40], [-40, 35], [35, 90]]) + _shared_utils.assert_array_equal(lat.bounds, [[-90, -40], [-40, 35], [35, 90]]) def test_points_to_edges_bounds_outside(self): lat = DimCoord([-90, 0, 90], units="degree", standard_name="latitude") lat.guess_bounds() - self.assertArrayEqual(lat.bounds, [[-90, -45], [-45, 45], [45, 90]]) + _shared_utils.assert_array_equal(lat.bounds, [[-90, -45], [-45, 45], [45, 90]]) def test_points_outside(self): lat = DimCoord([-100, 0, 120], units="degree", standard_name="latitude") lat.guess_bounds() - self.assertArrayEqual(lat.bounds, [[-150, -50], [-50, 60], [60, 180]]) + _shared_utils.assert_array_equal( + lat.bounds, [[-150, -50], [-50, 60], [60, 180]] + ) def test_points_inside_bounds_outside_wrong_unit(self): lat = DimCoord([-80, 0, 70], units="feet", standard_name="latitude") lat.guess_bounds() - self.assertArrayEqual(lat.bounds, [[-120, -40], [-40, 35], [35, 105]]) + _shared_utils.assert_array_equal( + lat.bounds, [[-120, -40], [-40, 35], [35, 105]] + ) def test_points_inside_bounds_outside_wrong_name(self): lat = DimCoord([-80, 0, 70], units="degree", standard_name="longitude") lat.guess_bounds() - self.assertArrayEqual(lat.bounds, [[-120, -40], [-40, 35], [35, 105]]) + _shared_utils.assert_array_equal( + lat.bounds, [[-120, -40], [-40, 35], [35, 105]] + ) def test_points_inside_bounds_outside_wrong_name_2(self): lat = DimCoord([-80, 0, 70], units="degree", long_name="other_latitude") lat.guess_bounds() - self.assertArrayEqual(lat.bounds, [[-120, -40], [-40, 35], [35, 105]]) + _shared_utils.assert_array_equal( + lat.bounds, [[-120, -40], [-40, 35], [35, 105]] + ) def test_guess_bounds_monthly_and_yearly(): @@ -311,7 +316,7 @@ def test_monthly_end_of_month(self): coord.guess_bounds(monthly=True) dates = units.num2date(coord.bounds) expected_dates = units.num2date(expected) - np.testing.assert_array_equal(dates, expected_dates) + _shared_utils.assert_array_equal(dates, expected_dates) def test_monthly_multiple_years(self): units = cf_units.Unit("days since epoch", calendar="gregorian") @@ -325,7 +330,7 @@ def test_monthly_multiple_years(self): coord = iris.coords.AuxCoord(points=points, units=units, standard_name="time") coord.guess_bounds(monthly=True) dates = units.num2date(coord.bounds) - np.testing.assert_array_equal(dates, expected) + _shared_utils.assert_array_equal(dates, expected) def test_monthly_single_point(self): units = cf_units.Unit("days since epoch", calendar="gregorian") @@ -337,7 +342,7 @@ def test_monthly_single_point(self): coord = iris.coords.AuxCoord(points=points, units=units, standard_name="time") coord.guess_bounds(monthly=True) dates = units.num2date(coord.bounds) - np.testing.assert_array_equal(dates, expected) + _shared_utils.assert_array_equal(dates, expected) class Test_Guess_Bounds_Yearly: @@ -394,48 +399,45 @@ def test_yearly_end_of_year(self): coord.guess_bounds(yearly=True) dates = units.num2date(coord.bounds) expected_dates = units.num2date(expected) - np.testing.assert_array_equal(dates, expected_dates) + _shared_utils.assert_array_equal(dates, expected_dates) -class Test_cell(tests.IrisTest): - def _mock_coord(self): - coord = mock.Mock( +class Test_cell: + def _mock_coord(self, mocker): + coord = mocker.Mock( spec=Coord, ndim=1, ) - coord.core_points = lambda: np.array([mock.sentinel.time]) + coord.core_points = lambda: np.array([mocker.sentinel.time]) coord.core_bounds = lambda: np.array( - [[mock.sentinel.lower, mock.sentinel.upper]] + [[mocker.sentinel.lower, mocker.sentinel.upper]] ) return coord - def test_time_as_object(self): + def test_time_as_object(self, mocker): # Ensure Coord.cell() converts the point/bound values to # "datetime" objects. - coord = self._mock_coord() - coord.units.num2date = mock.Mock( + coord = self._mock_coord(mocker) + coord.units.num2date = mocker.Mock( side_effect=[ - mock.sentinel.datetime, - (mock.sentinel.datetime_lower, mock.sentinel.datetime_upper), + mocker.sentinel.datetime, + (mocker.sentinel.datetime_lower, mocker.sentinel.datetime_upper), ] ) cell = Coord.cell(coord, 0) - self.assertIs(cell.point, mock.sentinel.datetime) - self.assertEqual( - cell.bound, - (mock.sentinel.datetime_lower, mock.sentinel.datetime_upper), - ) - self.assertEqual( - coord.units.num2date.call_args_list, - [ - mock.call((mock.sentinel.time,)), - mock.call((mock.sentinel.lower, mock.sentinel.upper)), - ], - ) + assert cell.point is mocker.sentinel.datetime + assert cell.bound == ( + mocker.sentinel.datetime_lower, + mocker.sentinel.datetime_upper, + ) + assert coord.units.num2date.call_args_list == [ + mocker.call((mocker.sentinel.time,)), + mocker.call((mocker.sentinel.lower, mocker.sentinel.upper)), + ] -class Test_collapsed(tests.IrisTest, CoordTestMixin): +class Test_collapsed(CoordTestMixin): def test_serialize(self): # Collapse a string AuxCoord, causing it to be serialised. string = Pair( @@ -468,11 +470,13 @@ def _serialize(data): for points, bounds in [string, string_nobounds, string_multi]: coord = AuxCoord(points=points, bounds=bounds, units=units) collapsed_coord = coord.collapsed() - self.assertArrayEqual(collapsed_coord.points, _serialize(points)) + _shared_utils.assert_array_equal( + collapsed_coord.points, _serialize(points) + ) if bounds is not None: for index in np.ndindex(bounds.shape[1:]): index_slice = (slice(None),) + tuple(index) - self.assertArrayEqual( + _shared_utils.assert_array_equal( collapsed_coord.bounds[index_slice], _serialize(bounds[index_slice]), ) @@ -485,10 +489,12 @@ def test_dim_1d(self): ) for units in ["unknown", "no_unit", 1, "K"]: coord.units = units - with self.assertNoWarningsRegexp(): + with _shared_utils.assert_no_warnings_regexp(): collapsed_coord = coord.collapsed() - self.assertArrayEqual(collapsed_coord.points, np.mean(coord.points)) - self.assertArrayEqual( + _shared_utils.assert_array_equal( + collapsed_coord.points, np.mean(coord.points) + ) + _shared_utils.assert_array_equal( collapsed_coord.bounds, [[coord.bounds.min(), coord.bounds.max()]], ) @@ -497,168 +503,174 @@ def test_lazy_points(self): # Lazy points should stay lazy after collapse. coord = AuxCoord(points=da.from_array(np.arange(5), chunks=5)) collapsed_coord = coord.collapsed() - self.assertTrue(collapsed_coord.has_lazy_bounds()) - self.assertTrue(collapsed_coord.has_lazy_points()) + assert collapsed_coord.has_lazy_bounds() + assert collapsed_coord.has_lazy_points() def test_numeric_nd(self): coord = AuxCoord(points=np.array([[1, 2, 4, 5], [4, 5, 7, 8], [7, 8, 10, 11]])) collapsed_coord = coord.collapsed() - self.assertArrayEqual(collapsed_coord.points, np.array([6])) - self.assertArrayEqual(collapsed_coord.bounds, np.array([[1, 11]])) + _shared_utils.assert_array_equal(collapsed_coord.points, np.array([6])) + _shared_utils.assert_array_equal(collapsed_coord.bounds, np.array([[1, 11]])) # Test partially collapsing one dimension... collapsed_coord = coord.collapsed(1) - self.assertArrayEqual(collapsed_coord.points, np.array([3.0, 6.0, 9.0])) - self.assertArrayEqual( + _shared_utils.assert_array_equal( + collapsed_coord.points, np.array([3.0, 6.0, 9.0]) + ) + _shared_utils.assert_array_equal( collapsed_coord.bounds, np.array([[1, 5], [4, 8], [7, 11]]) ) # ... and the other collapsed_coord = coord.collapsed(0) - self.assertArrayEqual(collapsed_coord.points, np.array([4, 5, 7, 8])) - self.assertArrayEqual( + _shared_utils.assert_array_equal(collapsed_coord.points, np.array([4, 5, 7, 8])) + _shared_utils.assert_array_equal( collapsed_coord.bounds, np.array([[1, 7], [2, 8], [4, 10], [5, 11]]), ) def test_numeric_nd_bounds_all(self): - self.setupTestArrays((3, 4)) + self.setup_test_arrays((3, 4)) coord = AuxCoord(self.pts_real, bounds=self.bds_real) collapsed_coord = coord.collapsed() - self.assertArrayEqual(collapsed_coord.points, np.array([55])) - self.assertArrayEqual(collapsed_coord.bounds, np.array([[-2, 112]])) + _shared_utils.assert_array_equal(collapsed_coord.points, np.array([55])) + _shared_utils.assert_array_equal(collapsed_coord.bounds, np.array([[-2, 112]])) def test_numeric_nd_bounds_second(self): - self.setupTestArrays((3, 4)) + self.setup_test_arrays((3, 4)) coord = AuxCoord(self.pts_real, bounds=self.bds_real) collapsed_coord = coord.collapsed(1) - self.assertArrayEqual(collapsed_coord.points, np.array([15, 55, 95])) - self.assertArrayEqual( + _shared_utils.assert_array_equal(collapsed_coord.points, np.array([15, 55, 95])) + _shared_utils.assert_array_equal( collapsed_coord.bounds, np.array([[-2, 32], [38, 72], [78, 112]]) ) def test_numeric_nd_bounds_first(self): - self.setupTestArrays((3, 4)) + self.setup_test_arrays((3, 4)) coord = AuxCoord(self.pts_real, bounds=self.bds_real) # ... and the other.. collapsed_coord = coord.collapsed(0) - self.assertArrayEqual(collapsed_coord.points, np.array([40, 50, 60, 70])) - self.assertArrayEqual( + _shared_utils.assert_array_equal( + collapsed_coord.points, np.array([40, 50, 60, 70]) + ) + _shared_utils.assert_array_equal( collapsed_coord.bounds, np.array([[-2, 82], [8, 92], [18, 102], [28, 112]]), ) def test_numeric_nd_bounds_last(self): - self.setupTestArrays((3, 4)) + self.setup_test_arrays((3, 4)) coord = AuxCoord(self.pts_real, bounds=self.bds_real) # ... and again with -ve dimension specification. collapsed_coord = coord.collapsed(-1) - self.assertArrayEqual(collapsed_coord.points, np.array([15, 55, 95])) - self.assertArrayEqual( + _shared_utils.assert_array_equal(collapsed_coord.points, np.array([15, 55, 95])) + _shared_utils.assert_array_equal( collapsed_coord.bounds, np.array([[-2, 32], [38, 72], [78, 112]]) ) def test_lazy_nd_bounds_all(self): - self.setupTestArrays((3, 4)) + self.setup_test_arrays((3, 4)) coord = AuxCoord(self.pts_real, bounds=self.bds_lazy) collapsed_coord = coord.collapsed() # Note that the new points get recalculated from the lazy bounds # and so end up as lazy - self.assertTrue(collapsed_coord.has_lazy_points()) - self.assertTrue(collapsed_coord.has_lazy_bounds()) + assert collapsed_coord.has_lazy_points() + assert collapsed_coord.has_lazy_bounds() - self.assertArrayEqual(collapsed_coord.points, np.array([55])) - self.assertArrayEqual(collapsed_coord.bounds, da.array([[-2, 112]])) + _shared_utils.assert_array_equal(collapsed_coord.points, np.array([55])) + _shared_utils.assert_array_equal(collapsed_coord.bounds, da.array([[-2, 112]])) def test_lazy_nd_bounds_second(self): - self.setupTestArrays((3, 4)) + self.setup_test_arrays((3, 4)) coord = AuxCoord(self.pts_real, bounds=self.bds_lazy) collapsed_coord = coord.collapsed(1) - self.assertArrayEqual(collapsed_coord.points, np.array([15, 55, 95])) - self.assertArrayEqual( + _shared_utils.assert_array_equal(collapsed_coord.points, np.array([15, 55, 95])) + _shared_utils.assert_array_equal( collapsed_coord.bounds, np.array([[-2, 32], [38, 72], [78, 112]]) ) def test_lazy_nd_bounds_first(self): - self.setupTestArrays((3, 4)) + self.setup_test_arrays((3, 4)) coord = AuxCoord(self.pts_real, bounds=self.bds_lazy) collapsed_coord = coord.collapsed(0) - self.assertArrayEqual(collapsed_coord.points, np.array([40, 50, 60, 70])) - self.assertArrayEqual( + _shared_utils.assert_array_equal( + collapsed_coord.points, np.array([40, 50, 60, 70]) + ) + _shared_utils.assert_array_equal( collapsed_coord.bounds, np.array([[-2, 82], [8, 92], [18, 102], [28, 112]]), ) def test_lazy_nd_bounds_last(self): - self.setupTestArrays((3, 4)) + self.setup_test_arrays((3, 4)) coord = AuxCoord(self.pts_real, bounds=self.bds_lazy) collapsed_coord = coord.collapsed(-1) - self.assertArrayEqual(collapsed_coord.points, np.array([15, 55, 95])) - self.assertArrayEqual( + _shared_utils.assert_array_equal(collapsed_coord.points, np.array([15, 55, 95])) + _shared_utils.assert_array_equal( collapsed_coord.bounds, np.array([[-2, 32], [38, 72], [78, 112]]) ) def test_lazy_nd_points_and_bounds(self): - self.setupTestArrays((3, 4)) + self.setup_test_arrays((3, 4)) coord = AuxCoord(self.pts_lazy, bounds=self.bds_lazy) collapsed_coord = coord.collapsed() - self.assertTrue(collapsed_coord.has_lazy_points()) - self.assertTrue(collapsed_coord.has_lazy_bounds()) + assert collapsed_coord.has_lazy_points() + assert collapsed_coord.has_lazy_bounds() - self.assertArrayEqual(collapsed_coord.points, da.array([55])) - self.assertArrayEqual(collapsed_coord.bounds, da.array([[-2, 112]])) + _shared_utils.assert_array_equal(collapsed_coord.points, da.array([55])) + _shared_utils.assert_array_equal(collapsed_coord.bounds, da.array([[-2, 112]])) def test_numeric_nd_multidim_bounds_warning(self): - self.setupTestArrays((3, 4)) + self.setup_test_arrays((3, 4)) coord = AuxCoord(self.pts_real, bounds=self.bds_real, long_name="y") msg = ( "Collapsing a multi-dimensional coordinate. " "Metadata may not be fully descriptive for 'y'." ) - with self.assertWarnsRegex(IrisVagueMetadataWarning, msg): + with pytest.warns(IrisVagueMetadataWarning, match=msg): coord.collapsed() def test_lazy_nd_multidim_bounds_warning(self): - self.setupTestArrays((3, 4)) + self.setup_test_arrays((3, 4)) coord = AuxCoord(self.pts_lazy, bounds=self.bds_lazy, long_name="y") msg = ( "Collapsing a multi-dimensional coordinate. " "Metadata may not be fully descriptive for 'y'." ) - with self.assertWarnsRegex(IrisVagueMetadataWarning, msg): + with pytest.warns(IrisVagueMetadataWarning, match=msg): coord.collapsed() def test_numeric_nd_noncontiguous_bounds_warning(self): - self.setupTestArrays((3)) + self.setup_test_arrays((3)) coord = AuxCoord(self.pts_real, bounds=self.bds_real, long_name="y") msg = ( "Collapsing a non-contiguous coordinate. " "Metadata may not be fully descriptive for 'y'." ) - with self.assertWarnsRegex(IrisVagueMetadataWarning, msg): + with pytest.warns(IrisVagueMetadataWarning, match=msg): coord.collapsed() def test_lazy_nd_noncontiguous_bounds_warning(self): - self.setupTestArrays((3)) + self.setup_test_arrays((3)) coord = AuxCoord(self.pts_lazy, bounds=self.bds_lazy, long_name="y") msg = ( "Collapsing a non-contiguous coordinate. " "Metadata may not be fully descriptive for 'y'." ) - with self.assertWarnsRegex(IrisVagueMetadataWarning, msg): + with pytest.warns(IrisVagueMetadataWarning, match=msg): coord.collapsed() def test_numeric_3_bounds(self): @@ -673,14 +685,16 @@ def test_numeric_3_bounds(self): r"1D coordinates with 2 bounds. Metadata may not be fully " r"descriptive for 'x'. Ignoring bounds." ) - with self.assertWarnsRegex(IrisVagueMetadataWarning, msg): + with pytest.warns(IrisVagueMetadataWarning, match=msg): collapsed_coord = coord.collapsed() - self.assertFalse(collapsed_coord.has_lazy_points()) - self.assertFalse(collapsed_coord.has_lazy_bounds()) + assert not collapsed_coord.has_lazy_points() + assert not collapsed_coord.has_lazy_bounds() - self.assertArrayAlmostEqual(collapsed_coord.points, np.array([4.0])) - self.assertArrayAlmostEqual(collapsed_coord.bounds, np.array([[2.0, 6.0]])) + _shared_utils.assert_array_almost_equal(collapsed_coord.points, np.array([4.0])) + _shared_utils.assert_array_almost_equal( + collapsed_coord.bounds, np.array([[2.0, 6.0]]) + ) def test_lazy_3_bounds(self): points = da.arange(3) * 2.0 @@ -694,14 +708,16 @@ def test_lazy_3_bounds(self): r"1D coordinates with 2 bounds. Metadata may not be fully " r"descriptive for 'x'. Ignoring bounds." ) - with self.assertWarnsRegex(IrisVagueMetadataWarning, msg): + with pytest.warns(IrisVagueMetadataWarning, match=msg): collapsed_coord = coord.collapsed() - self.assertTrue(collapsed_coord.has_lazy_points()) - self.assertTrue(collapsed_coord.has_lazy_bounds()) + assert collapsed_coord.has_lazy_points() + assert collapsed_coord.has_lazy_bounds() - self.assertArrayAlmostEqual(collapsed_coord.points, da.array([2.0])) - self.assertArrayAlmostEqual(collapsed_coord.bounds, da.array([[0.0, 4.0]])) + _shared_utils.assert_array_almost_equal(collapsed_coord.points, da.array([2.0])) + _shared_utils.assert_array_almost_equal( + collapsed_coord.bounds, da.array([[0.0, 4.0]]) + ) def test_string_masked(self): points = ma.array(["foo", "bar", "bing"], mask=[0, 1, 0], dtype=str) @@ -710,10 +726,10 @@ def test_string_masked(self): collapsed_coord = coord.collapsed(0) expected = "foo|--|bing" - self.assertEqual(collapsed_coord.points, expected) + assert collapsed_coord.points == expected def test_string_nd_first(self): - self.setupTestArrays((3, 4)) + self.setup_test_arrays((3, 4)) coord = AuxCoord(self.pts_real.astype(str)) collapsed_coord = coord.collapsed(0) @@ -724,10 +740,10 @@ def test_string_nd_first(self): "30.0|70.0|110.0", ] - self.assertArrayEqual(collapsed_coord.points, expected) + _shared_utils.assert_array_equal(collapsed_coord.points, expected) def test_string_nd_second(self): - self.setupTestArrays((3, 4)) + self.setup_test_arrays((3, 4)) coord = AuxCoord(self.pts_real.astype(str)) collapsed_coord = coord.collapsed(1) @@ -737,19 +753,19 @@ def test_string_nd_second(self): "80.0|90.0|100.0|110.0", ] - self.assertArrayEqual(collapsed_coord.points, expected) + _shared_utils.assert_array_equal(collapsed_coord.points, expected) def test_string_nd_both(self): - self.setupTestArrays((3, 4)) + self.setup_test_arrays((3, 4)) coord = AuxCoord(self.pts_real.astype(str)) collapsed_coord = coord.collapsed() expected = ["0.0|10.0|20.0|30.0|40.0|50.0|60.0|70.0|80.0|90.0|100.0|110.0"] - self.assertArrayEqual(collapsed_coord.points, expected) + _shared_utils.assert_array_equal(collapsed_coord.points, expected) def test_string_nd_bounds_first(self): - self.setupTestArrays((3, 4)) + self.setup_test_arrays((3, 4)) coord = AuxCoord(self.pts_real.astype(str), bounds=self.bds_real.astype(str)) collapsed_coord = coord.collapsed(0) @@ -769,11 +785,11 @@ def test_string_nd_bounds_first(self): "32.0|72.0|112.0", ] - self.assertArrayEqual(collapsed_coord.bounds[:, 0], expected_lower) - self.assertArrayEqual(collapsed_coord.bounds[:, 1], expected_upper) + _shared_utils.assert_array_equal(collapsed_coord.bounds[:, 0], expected_lower) + _shared_utils.assert_array_equal(collapsed_coord.bounds[:, 1], expected_upper) def test_string_nd_bounds_second(self): - self.setupTestArrays((3, 4)) + self.setup_test_arrays((3, 4)) coord = AuxCoord(self.pts_real.astype(str), bounds=self.bds_real.astype(str)) collapsed_coord = coord.collapsed(1) @@ -791,11 +807,11 @@ def test_string_nd_bounds_second(self): "82.0|92.0|102.0|112.0", ] - self.assertArrayEqual(collapsed_coord.bounds[:, 0], expected_lower) - self.assertArrayEqual(collapsed_coord.bounds[:, 1], expected_upper) + _shared_utils.assert_array_equal(collapsed_coord.bounds[:, 0], expected_lower) + _shared_utils.assert_array_equal(collapsed_coord.bounds[:, 1], expected_upper) def test_string_nd_bounds_both(self): - self.setupTestArrays((3, 4)) + self.setup_test_arrays((3, 4)) coord = AuxCoord(self.pts_real.astype(str), bounds=self.bds_real.astype(str)) collapsed_coord = coord.collapsed() @@ -806,53 +822,51 @@ def test_string_nd_bounds_both(self): "2.0|12.0|22.0|32.0|42.0|52.0|62.0|72.0|82.0|92.0|102.0|112.0" ] - self.assertArrayEqual(collapsed_coord.bounds[:, 0], expected_lower) - self.assertArrayEqual(collapsed_coord.bounds[:, 1], expected_upper) + _shared_utils.assert_array_equal(collapsed_coord.bounds[:, 0], expected_lower) + _shared_utils.assert_array_equal(collapsed_coord.bounds[:, 1], expected_upper) -class Test_is_compatible(tests.IrisTest): - def setUp(self): +class Test_is_compatible: + @pytest.fixture(autouse=True) + def _setup(self): self.test_coord = AuxCoord([1.0]) self.other_coord = self.test_coord.copy() def test_noncommon_array_attrs_compatible(self): # Non-common array attributes should be ok. self.test_coord.attributes["array_test"] = np.array([1.0, 2, 3]) - self.assertTrue(self.test_coord.is_compatible(self.other_coord)) + assert self.test_coord.is_compatible(self.other_coord) def test_matching_array_attrs_compatible(self): # Matching array attributes should be ok. self.test_coord.attributes["array_test"] = np.array([1.0, 2, 3]) self.other_coord.attributes["array_test"] = np.array([1.0, 2, 3]) - self.assertTrue(self.test_coord.is_compatible(self.other_coord)) + assert self.test_coord.is_compatible(self.other_coord) def test_different_array_attrs_incompatible(self): # Differing array attributes should make coords incompatible. self.test_coord.attributes["array_test"] = np.array([1.0, 2, 3]) self.other_coord.attributes["array_test"] = np.array([1.0, 2, 777.7]) - self.assertFalse(self.test_coord.is_compatible(self.other_coord)) + assert not self.test_coord.is_compatible(self.other_coord) -class Test_contiguous_bounds(tests.IrisTest): +class Test_contiguous_bounds: def test_1d_coord_no_bounds_warning(self): coord = DimCoord([0, 1, 2], standard_name="latitude") msg = "Coordinate 'latitude' is not bounded, guessing contiguous bounds." - with warnings.catch_warnings(): - # Cause all warnings to raise Exceptions - warnings.simplefilter("error") - with self.assertRaisesRegex(Warning, msg): - coord.contiguous_bounds() + with pytest.warns(match=msg): + coord.contiguous_bounds() def test_2d_coord_no_bounds_error(self): coord = AuxCoord(np.array([[0, 0], [5, 5]]), standard_name="latitude") emsg = "Guessing bounds of 2D coords is not currently supported" - with self.assertRaisesRegex(ValueError, emsg): + with pytest.raises(ValueError, match=emsg): coord.contiguous_bounds() - def test__sanity_check_bounds_call(self): + def test__sanity_check_bounds_call(self, mocker): coord = DimCoord([5, 15, 25], bounds=[[0, 10], [10, 20], [20, 30]]) - with mock.patch("iris.coords.Coord._sanity_check_bounds") as bounds_check: - coord.contiguous_bounds() + bounds_check = mocker.patch("iris.coords.Coord._sanity_check_bounds") + coord.contiguous_bounds() bounds_check.assert_called_once() def test_1d_coord(self): @@ -863,7 +877,7 @@ def test_1d_coord(self): ) expected = np.array([1, 3, 5, 7]) result = coord.contiguous_bounds() - self.assertArrayEqual(result, expected) + _shared_utils.assert_array_equal(result, expected) def test_1d_coord_discontiguous(self): coord = DimCoord( @@ -873,7 +887,7 @@ def test_1d_coord_discontiguous(self): ) expected = np.array([1, 4, 5, 7]) result = coord.contiguous_bounds() - self.assertArrayEqual(result, expected) + _shared_utils.assert_array_equal(result, expected) def test_2d_lon_bounds(self): coord = AuxCoord( @@ -884,7 +898,7 @@ def test_2d_lon_bounds(self): ) expected = np.array([[0, 2, 4], [0, 2, 4], [0, 2, 4]]) result = coord.contiguous_bounds() - self.assertArrayEqual(result, expected) + _shared_utils.assert_array_equal(result, expected) def test_2d_lat_bounds(self): coord = AuxCoord( @@ -895,31 +909,31 @@ def test_2d_lat_bounds(self): ) expected = np.array([[0, 0, 0], [2, 2, 2], [4, 4, 4]]) result = coord.contiguous_bounds() - self.assertArrayEqual(result, expected) + _shared_utils.assert_array_equal(result, expected) -class Test_is_contiguous(tests.IrisTest): +class Test_is_contiguous: def test_no_bounds(self): coord = DimCoord([1, 3]) result = coord.is_contiguous() - self.assertFalse(result) + assert not result - def test__discontiguity_in_bounds_call(self): + def test__discontiguity_in_bounds_call(self, mocker): # Check that :meth:`iris.coords.Coord._discontiguity_in_bounds` is # called. coord = DimCoord([1, 3], bounds=[[0, 2], [2, 4]]) - with mock.patch( - "iris.coords.Coord._discontiguity_in_bounds" - ) as discontiguity_check: - # Discontiguity returns two objects that are unpacked in - # `coord.is_contiguous`. - discontiguity_check.return_value = [None, None] - coord.is_contiguous(rtol=1e-1, atol=1e-3) + + discontiguity_check = mocker.patch("iris.coords.Coord._discontiguity_in_bounds") + # Discontiguity returns two objects that are unpacked in + # `coord.is_contiguous`. + discontiguity_check.return_value = [None, None] + coord.is_contiguous(rtol=1e-1, atol=1e-3) discontiguity_check.assert_called_with(rtol=1e-1, atol=1e-3) -class Test__discontiguity_in_bounds(tests.IrisTest): - def setUp(self): +class Test__discontiguity_in_bounds: + @pytest.fixture(autouse=True) + def _setup(self): self.points_3by3 = np.array([[1, 2, 3], [1, 2, 3], [1, 2, 3]]) self.lon_bounds_3by3 = np.array( [ @@ -939,29 +953,29 @@ def setUp(self): def test_1d_contiguous(self): coord = DimCoord([-20, 0, 20], bounds=[[-30, -10], [-10, 10], [10, 30]]) contiguous, diffs = coord._discontiguity_in_bounds() - self.assertTrue(contiguous) - self.assertArrayEqual(diffs, np.zeros(2)) + assert contiguous + _shared_utils.assert_array_equal(diffs, np.zeros(2)) def test_1d_discontiguous(self): coord = DimCoord([10, 20, 40], bounds=[[5, 15], [15, 25], [35, 45]]) contiguous, diffs = coord._discontiguity_in_bounds() - self.assertFalse(contiguous) - self.assertArrayEqual(diffs, np.array([False, True])) + assert not contiguous + _shared_utils.assert_array_equal(diffs, np.array([False, True])) def test_1d_one_cell(self): # Test a 1D coord with a single cell. coord = DimCoord(20, bounds=[[10, 30]]) contiguous, diffs = coord._discontiguity_in_bounds() - self.assertTrue(contiguous) - self.assertArrayEqual(diffs, np.array([])) + assert contiguous + _shared_utils.assert_array_equal(diffs, np.array([])) def test_2d_contiguous_both_dirs(self): coord = AuxCoord(self.points_3by3, bounds=self.lon_bounds_3by3) contiguous, diffs = coord._discontiguity_in_bounds() diffs_along_x, diffs_along_y = diffs - self.assertTrue(contiguous) - self.assertTrue(not diffs_along_x.any()) - self.assertTrue(not diffs_along_y.any()) + assert contiguous + assert not diffs_along_x.any() + assert not diffs_along_y.any() def test_2d_discontiguous_along_x(self): coord = AuxCoord( @@ -969,9 +983,11 @@ def test_2d_discontiguous_along_x(self): ) contiguous, diffs = coord._discontiguity_in_bounds() diffs_along_x, diffs_along_y = diffs - self.assertFalse(contiguous) - self.assertArrayEqual(diffs_along_x, np.array([True, True, True]).reshape(3, 1)) - self.assertTrue(not diffs_along_y.any()) + assert not contiguous + _shared_utils.assert_array_equal( + diffs_along_x, np.array([True, True, True]).reshape(3, 1) + ) + assert not diffs_along_y.any() def test_2d_discontiguous_along_y(self): coord = AuxCoord( @@ -979,9 +995,9 @@ def test_2d_discontiguous_along_y(self): ) contiguous, diffs = coord._discontiguity_in_bounds() diffs_along_x, diffs_along_y = diffs - self.assertFalse(contiguous) - self.assertTrue(not diffs_along_x.any()) - self.assertArrayEqual(diffs_along_y, np.array([[True, True, True]])) + assert not contiguous + assert not diffs_along_x.any() + _shared_utils.assert_array_equal(diffs_along_y, np.array([[True, True, True]])) def test_2d_discontiguous_along_x_and_y(self): coord = AuxCoord( @@ -994,9 +1010,9 @@ def test_2d_discontiguous_along_x_and_y(self): diffs_along_x, diffs_along_y = diffs exp_x_diffs = np.array([True, False]).reshape(2, 1) exp_y_diffs = np.array([True, False]).reshape(1, 2) - self.assertFalse(contiguous) - self.assertArrayEqual(diffs_along_x, exp_x_diffs) - self.assertArrayEqual(diffs_along_y, exp_y_diffs) + assert not contiguous + _shared_utils.assert_array_equal(diffs_along_x, exp_x_diffs) + _shared_utils.assert_array_equal(diffs_along_y, exp_y_diffs) def test_2d_contiguous_along_x_atol(self): coord = AuxCoord( @@ -1005,11 +1021,11 @@ def test_2d_contiguous_along_x_atol(self): # Set a high atol that allows small discontiguities. contiguous, diffs = coord._discontiguity_in_bounds(atol=5) diffs_along_x, diffs_along_y = diffs - self.assertTrue(contiguous) - self.assertArrayEqual( + assert contiguous + _shared_utils.assert_array_equal( diffs_along_x, np.array([False, False, False]).reshape(3, 1) ) - self.assertTrue(not diffs_along_y.any()) + assert not diffs_along_y.any() def test_2d_one_cell(self): # Test a 2D coord with a single cell, where the coord has shape (1, 1). @@ -1019,9 +1035,9 @@ def test_2d_one_cell(self): contiguous, diffs = coord._discontiguity_in_bounds() diffs_along_x, diffs_along_y = diffs expected_diffs = np.array([], dtype=np.int64) - self.assertTrue(contiguous) - self.assertArrayEqual(diffs_along_x, expected_diffs.reshape(1, 0)) - self.assertArrayEqual(diffs_along_y, expected_diffs.reshape(0, 1)) + assert contiguous + _shared_utils.assert_array_equal(diffs_along_x, expected_diffs.reshape(1, 0)) + _shared_utils.assert_array_equal(diffs_along_y, expected_diffs.reshape(0, 1)) def test_2d_one_cell_along_x(self): # Test a 2D coord with a single cell along the x axis, where the coord @@ -1029,9 +1045,9 @@ def test_2d_one_cell_along_x(self): coord = AuxCoord(self.points_3by3[:, :1], bounds=self.lat_bounds_3by3[:, :1, :]) contiguous, diffs = coord._discontiguity_in_bounds() diffs_along_x, diffs_along_y = diffs - self.assertTrue(contiguous) - self.assertTrue(not diffs_along_x.any()) - self.assertArrayEqual(diffs_along_y, np.array([0, 0]).reshape(2, 1)) + assert contiguous + assert not diffs_along_x.any() + _shared_utils.assert_array_equal(diffs_along_y, np.array([0, 0]).reshape(2, 1)) def test_2d_one_cell_along_y(self): # Test a 2D coord with a single cell along the y axis, where the coord @@ -1039,9 +1055,9 @@ def test_2d_one_cell_along_y(self): coord = AuxCoord(self.points_3by3[:1, :], bounds=self.lon_bounds_3by3[:1, :, :]) contiguous, diffs = coord._discontiguity_in_bounds() diffs_along_x, diffs_along_y = diffs - self.assertTrue(contiguous) - self.assertTrue(not diffs_along_x.any()) - self.assertTrue(not diffs_along_y.any()) + assert contiguous + assert not diffs_along_x.any() + assert not diffs_along_y.any() def test_2d_contiguous_mod_360(self): # Test that longitude coordinates are adjusted by the 360 modulus when @@ -1058,9 +1074,9 @@ def test_2d_contiguous_mod_360(self): ) contiguous, diffs = coord._discontiguity_in_bounds() diffs_along_x, diffs_along_y = diffs - self.assertTrue(contiguous) - self.assertTrue(not diffs_along_x.any()) - self.assertTrue(not diffs_along_y.any()) + assert contiguous + assert not diffs_along_x.any() + assert not diffs_along_y.any() def test_2d_discontiguous_mod_360(self): # Test that longitude coordinates are adjusted by the 360 modulus when @@ -1077,9 +1093,9 @@ def test_2d_discontiguous_mod_360(self): ) contiguous, diffs = coord._discontiguity_in_bounds() diffs_along_x, diffs_along_y = diffs - self.assertFalse(contiguous) - self.assertArrayEqual(diffs_along_x, np.array([[True], [True]])) - self.assertTrue(not diffs_along_y.any()) + assert not contiguous + _shared_utils.assert_array_equal(diffs_along_x, np.array([[True], [True]])) + assert not diffs_along_y.any() def test_2d_contiguous_mod_360_not_longitude(self): # Test that non-longitude coordinates are not adjusted by the 360 @@ -1096,9 +1112,9 @@ def test_2d_contiguous_mod_360_not_longitude(self): ) contiguous, diffs = coord._discontiguity_in_bounds() diffs_along_x, diffs_along_y = diffs - self.assertTrue(contiguous) - self.assertTrue(not diffs_along_x.any()) - self.assertTrue(not diffs_along_y.any()) + assert contiguous + assert not diffs_along_x.any() + assert not diffs_along_y.any() def test_2d_discontiguous_mod_360_not_longitude(self): # Test that non-longitude coordinates are not adjusted by the 360 @@ -1115,12 +1131,12 @@ def test_2d_discontiguous_mod_360_not_longitude(self): ) contiguous, diffs = coord._discontiguity_in_bounds() diffs_along_x, diffs_along_y = diffs - self.assertFalse(contiguous) - self.assertArrayEqual(diffs_along_x, np.array([[True], [True]])) - self.assertTrue(not diffs_along_y.any()) + assert not contiguous + _shared_utils.assert_array_equal(diffs_along_x, np.array([[True], [True]])) + assert not diffs_along_y.any() -class Test__sanity_check_bounds(tests.IrisTest): +class Test__sanity_check_bounds: def test_coord_1d_2_bounds(self): # Check that a 1d coord with 2 bounds does not raise an error. coord = iris.coords.DimCoord( @@ -1131,7 +1147,7 @@ def test_coord_1d_2_bounds(self): def test_coord_1d_no_bounds(self): coord = iris.coords.DimCoord([0, 1], standard_name="latitude") emsg = "Contiguous bounds are only defined for 1D coordinates with 2 bounds." - with self.assertRaisesRegex(ValueError, emsg): + with pytest.raises(ValueError, match=emsg): coord._sanity_check_bounds() def test_coord_1d_1_bounds(self): @@ -1139,7 +1155,7 @@ def test_coord_1d_1_bounds(self): [0, 1], standard_name="latitude", bounds=np.array([[0], [1]]) ) emsg = "Contiguous bounds are only defined for 1D coordinates with 2 bounds." - with self.assertRaisesRegex(ValueError, emsg): + with pytest.raises(ValueError, match=emsg): coord._sanity_check_bounds() def test_coord_2d_4_bounds(self): @@ -1155,7 +1171,7 @@ def test_coord_2d_4_bounds(self): def test_coord_2d_no_bounds(self): coord = iris.coords.AuxCoord([[0, 0], [1, 1]], standard_name="latitude") emsg = "Contiguous bounds are only defined for 2D coordinates with 4 bounds." - with self.assertRaisesRegex(ValueError, emsg): + with pytest.raises(ValueError, match=emsg): coord._sanity_check_bounds() def test_coord_2d_2_bounds(self): @@ -1165,7 +1181,7 @@ def test_coord_2d_2_bounds(self): bounds=np.array([[[0, 1], [0, 1]], [[1, 2], [1, 2]]]), ) emsg = "Contiguous bounds are only defined for 2D coordinates with 4 bounds." - with self.assertRaisesRegex(ValueError, emsg): + with pytest.raises(ValueError, match=emsg): coord._sanity_check_bounds() def test_coord_3d(self): @@ -1174,7 +1190,7 @@ def test_coord_3d(self): "Contiguous bounds are not defined for coordinates with more " "than 2 dimensions." ) - with self.assertRaisesRegex(ValueError, emsg): + with pytest.raises(ValueError, match=emsg): coord._sanity_check_bounds() @@ -1208,7 +1224,7 @@ def test_convert_attributes(self, attribute): ) -class Test___str__(tests.IrisTest): +class Test___str__: def test_short_time_interval(self): coord = DimCoord([5], standard_name="time", units="days since 1970-01-01") expected = "\n".join( @@ -1221,7 +1237,7 @@ def test_short_time_interval(self): ] ) result = coord.__str__() - self.assertEqual(expected, result) + assert expected == result def test_short_time_interval__bounded(self): coord = DimCoord([5, 6], standard_name="time", units="days since 1970-01-01") @@ -1239,7 +1255,7 @@ def test_short_time_interval__bounded(self): ] ) result = coord.__str__() - self.assertEqual(expected, result) + assert expected == result def test_long_time_interval(self): coord = DimCoord([5], standard_name="time", units="years since 1970-01-01") @@ -1253,7 +1269,7 @@ def test_long_time_interval(self): ] ) result = coord.__str__() - self.assertEqual(expected, result) + assert expected == result def test_long_time_interval__bounded(self): coord = DimCoord([5, 6], standard_name="time", units="years since 1970-01-01") @@ -1271,7 +1287,7 @@ def test_long_time_interval__bounded(self): ] ) result = coord.__str__() - self.assertEqual(expected, result) + assert expected == result def test_non_time_unit(self): coord = DimCoord([1.0]) @@ -1284,10 +1300,10 @@ def test_non_time_unit(self): ] ) result = coord.__str__() - self.assertEqual(expected, result) + assert expected == result -class TestClimatology(tests.IrisTest): +class TestClimatology: # Variety of tests for the climatological property of a coord. # Only using AuxCoord since there is no different behaviour between Aux # and DimCoords for this property. @@ -1299,10 +1315,10 @@ def test_create(self): units="days since 1970-01-01", climatological=True, ) - self.assertTrue(coord.climatological) + assert coord.climatological def test_create_no_bounds_no_set(self): - with self.assertRaisesRegex(ValueError, "Cannot set.*no bounds exist"): + with pytest.raises(ValueError, match="Cannot set.*no bounds exist"): AuxCoord( points=[0, 1], units="days since 1970-01-01", @@ -1311,28 +1327,28 @@ def test_create_no_bounds_no_set(self): def test_create_no_time_no_set(self): emsg = "Cannot set climatological .* valid time reference units.*" - with self.assertRaisesRegex(TypeError, emsg): + with pytest.raises(TypeError, match=emsg): AuxCoord(points=[0, 1], bounds=[[0, 1], [1, 2]], climatological=True) def test_absent(self): coord = AuxCoord(points=[0, 1], bounds=[[0, 1], [1, 2]]) - self.assertFalse(coord.climatological) + assert not coord.climatological def test_absent_no_bounds_no_set(self): coord = AuxCoord(points=[0, 1], units="days since 1970-01-01") - with self.assertRaisesRegex(ValueError, "Cannot set.*no bounds exist"): + with pytest.raises(ValueError, match="Cannot set.*no bounds exist"): coord.climatological = True def test_absent_no_time_no_set(self): coord = AuxCoord(points=[0, 1], bounds=[[0, 1], [1, 2]]) emsg = "Cannot set climatological .* valid time reference units.*" - with self.assertRaisesRegex(TypeError, emsg): + with pytest.raises(TypeError, match=emsg): coord.climatological = True def test_absent_no_bounds_unset(self): coord = AuxCoord(points=[0, 1]) coord.climatological = False - self.assertFalse(coord.climatological) + assert not coord.climatological def test_bounds_set(self): coord = AuxCoord( @@ -1341,7 +1357,7 @@ def test_bounds_set(self): units="days since 1970-01-01", ) coord.climatological = True - self.assertTrue(coord.climatological) + assert coord.climatological def test_bounds_unset(self): coord = AuxCoord( @@ -1351,7 +1367,7 @@ def test_bounds_unset(self): climatological=True, ) coord.climatological = False - self.assertFalse(coord.climatological) + assert not coord.climatological def test_remove_bounds(self): coord = AuxCoord( @@ -1361,7 +1377,7 @@ def test_remove_bounds(self): climatological=True, ) coord.bounds = None - self.assertFalse(coord.climatological) + assert not coord.climatological def test_change_units(self): coord = AuxCoord( @@ -1370,9 +1386,9 @@ def test_change_units(self): units="days since 1970-01-01", climatological=True, ) - self.assertTrue(coord.climatological) + assert coord.climatological coord.units = "K" - self.assertFalse(coord.climatological) + assert not coord.climatological class TestIgnoreAxis: @@ -1391,7 +1407,7 @@ def test_set_random_value(self, sample_coord): sample_coord.ignore_axis = "foo" @pytest.mark.parametrize( - "ignore_axis, copy_or_from, result", + ("ignore_axis", "copy_or_from", "result"), [ (True, "copy", True), (True, "from_coord", True), @@ -1408,25 +1424,21 @@ def test_copy_coord(self, ignore_axis, copy_or_from, result, sample_coord): assert new_coord.ignore_axis is result -class Test___init____abstractmethod(tests.IrisTest): - def test(self): +class Test___init____abstractmethod: + def test_abstract(self): emsg = "Can't instantiate abstract class Coord" - with self.assertRaisesRegex(TypeError, emsg): + with pytest.raises(TypeError, match=emsg): _ = Coord(points=[0, 1]) -class Test_cube_dims(tests.IrisTest): - def test(self): +class Test_cube_dims: + def test_cube_dims(self, mocker): # Check that "coord.cube_dims(cube)" calls "cube.coord_dims(coord)". - mock_dims_result = mock.sentinel.COORD_DIMS - mock_dims_call = mock.Mock(return_value=mock_dims_result) - mock_cube = mock.Mock(Cube, coord_dims=mock_dims_call) + mock_dims_result = mocker.sentinel.COORD_DIMS + mock_dims_call = mocker.Mock(return_value=mock_dims_result) + mock_cube = mocker.Mock(Cube, coord_dims=mock_dims_call) test_coord = AuxCoord([1], long_name="test_name") result = test_coord.cube_dims(mock_cube) - self.assertEqual(result, mock_dims_result) - self.assertEqual(mock_dims_call.call_args_list, [mock.call(test_coord)]) - - -if __name__ == "__main__": - tests.main() + assert result == mock_dims_result + assert mock_dims_call.call_args_list == [mocker.call(test_coord)] diff --git a/lib/iris/tests/unit/coords/test_DimCoord.py b/lib/iris/tests/unit/coords/test_DimCoord.py index aac5defd23..a71f2ee3e5 100644 --- a/lib/iris/tests/unit/coords/test_DimCoord.py +++ b/lib/iris/tests/unit/coords/test_DimCoord.py @@ -9,14 +9,12 @@ """ -# Import iris.tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests # isort:skip - import numpy as np import numpy.ma as ma +import pytest from iris.coords import DimCoord +from iris.tests import _shared_utils from iris.tests.unit.coords import ( CoordTestMixin, coords_all_dtypes_and_lazynesses, @@ -26,15 +24,16 @@ class DimCoordTestMixin(CoordTestMixin): # Define a 1-D default array shape. - def setupTestArrays(self, shape=(3,), masked=False): - super().setupTestArrays(shape, masked=masked) + def setup_test_arrays(self, shape=(3,), masked=False): + super().setup_test_arrays(shape, masked=masked) -class Test__init__(tests.IrisTest, DimCoordTestMixin): +class Test__init__(DimCoordTestMixin): # Test for DimCoord creation, with various combinations of points and # bounds = real / lazy / None. - def setUp(self): - self.setupTestArrays(masked=True) + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays(masked=True) def test_lazyness_and_dtype_combinations(self): for ( @@ -46,123 +45,124 @@ def test_lazyness_and_dtype_combinations(self): bds = coord.core_bounds() # Check properties of points. # Points array should not be identical to the reference one. - self.assertArraysDoNotShareData( + self.assert_arrays_do_not_share_data( pts, self.pts_real, "Points are the same data as the provided array.", ) # the original points array was cast to a test dtype. check_pts = self.pts_real.astype(coord.dtype) - self.assertEqualRealArraysAndDtypes(pts, check_pts) + self.assert_equal_real_arrays_and_dtypes(pts, check_pts) # Check properties of bounds. if bounds_type_name != "no": # Bounds array should not be the reference data. - self.assertArraysDoNotShareData( + self.assert_arrays_do_not_share_data( bds, self.bds_real, "Bounds are the same data as the provided array.", ) # the original bounds array was cast to a test dtype. check_bds = self.bds_real.astype(coord.bounds_dtype) - self.assertEqualRealArraysAndDtypes(bds, check_bds) + self.assert_equal_real_arrays_and_dtypes(bds, check_bds) def test_fail_bounds_shape_mismatch(self): bds_shape = list(self.bds_real.shape) bds_shape[0] += 1 bds_wrong = np.zeros(bds_shape) msg = "The shape of the 'unknown' DimCoord bounds array should be" - with self.assertRaisesRegex(ValueError, msg): + with pytest.raises(ValueError, match=msg): DimCoord(self.pts_real, bounds=bds_wrong) def test_fail_nonmonotonic(self): msg = "must be strictly monotonic" - with self.assertRaisesRegex(ValueError, msg): + with pytest.raises(ValueError, match=msg): DimCoord([1, 2, 0, 3]) def test_no_masked_pts_real(self): data = self.no_masked_pts_real - self.assertTrue(ma.isMaskedArray(data)) - self.assertEqual(ma.count_masked(data), 0) + assert ma.isMaskedArray(data) + assert ma.count_masked(data) == 0 coord = DimCoord(data) - self.assertFalse(coord.has_lazy_points()) - self.assertFalse(ma.isMaskedArray(coord.points)) - self.assertEqual(ma.count_masked(coord.points), 0) + assert not coord.has_lazy_points() + assert not ma.isMaskedArray(coord.points) + assert ma.count_masked(coord.points) == 0 def test_no_masked_pts_lazy(self): data = self.no_masked_pts_lazy computed = data.compute() - self.assertTrue(ma.isMaskedArray(computed)) - self.assertEqual(ma.count_masked(computed), 0) + assert ma.isMaskedArray(computed) + assert ma.count_masked(computed) == 0 coord = DimCoord(data) # DimCoord always realises its points. - self.assertFalse(coord.has_lazy_points()) - self.assertFalse(ma.isMaskedArray(coord.points)) + assert not coord.has_lazy_points() + assert not ma.isMaskedArray(coord.points) def test_masked_pts_real(self): data = self.masked_pts_real - self.assertTrue(ma.isMaskedArray(data)) - self.assertTrue(ma.count_masked(data)) + assert ma.isMaskedArray(data) + assert ma.count_masked(data) emsg = "points array must not be masked" - with self.assertRaisesRegex(TypeError, emsg): + with pytest.raises(TypeError, match=emsg): DimCoord(data) def test_masked_pts_lazy(self): data = self.masked_pts_lazy computed = data.compute() - self.assertTrue(ma.isMaskedArray(computed)) - self.assertTrue(ma.count_masked(computed)) + assert ma.isMaskedArray(computed) + assert ma.count_masked(computed) emsg = "points array must not be masked" - with self.assertRaisesRegex(TypeError, emsg): + with pytest.raises(TypeError, match=emsg): DimCoord(data) def test_no_masked_bds_real(self): data = self.no_masked_bds_real - self.assertTrue(ma.isMaskedArray(data)) - self.assertEqual(ma.count_masked(data), 0) + assert ma.isMaskedArray(data) + assert ma.count_masked(data) == 0 coord = DimCoord(self.pts_real, bounds=data) - self.assertFalse(coord.has_lazy_bounds()) - self.assertFalse(ma.isMaskedArray(coord.bounds)) - self.assertEqual(ma.count_masked(coord.bounds), 0) + assert not coord.has_lazy_bounds() + assert not ma.isMaskedArray(coord.bounds) + assert ma.count_masked(coord.bounds) == 0 def test_no_masked_bds_lazy(self): data = self.no_masked_bds_lazy computed = data.compute() - self.assertTrue(ma.isMaskedArray(computed)) - self.assertEqual(ma.count_masked(computed), 0) + assert ma.isMaskedArray(computed) + assert ma.count_masked(computed) == 0 coord = DimCoord(self.pts_real, bounds=data) # DimCoord always realises its bounds. - self.assertFalse(coord.has_lazy_bounds()) - self.assertFalse(ma.isMaskedArray(coord.bounds)) + assert not coord.has_lazy_bounds() + assert not ma.isMaskedArray(coord.bounds) def test_masked_bds_real(self): data = self.masked_bds_real - self.assertTrue(ma.isMaskedArray(data)) - self.assertTrue(ma.count_masked(data)) + assert ma.isMaskedArray(data) + assert ma.count_masked(data) emsg = "bounds array must not be masked" - with self.assertRaisesRegex(TypeError, emsg): + with pytest.raises(TypeError, match=emsg): DimCoord(self.pts_real, bounds=data) def test_masked_bds_lazy(self): data = self.masked_bds_lazy computed = data.compute() - self.assertTrue(ma.isMaskedArray(computed)) - self.assertTrue(ma.count_masked(computed)) + assert ma.isMaskedArray(computed) + assert ma.count_masked(computed) emsg = "bounds array must not be masked" - with self.assertRaisesRegex(TypeError, emsg): + with pytest.raises(TypeError, match=emsg): DimCoord(self.pts_real, bounds=data) -class Test_core_points(tests.IrisTest, DimCoordTestMixin): +class Test_core_points(DimCoordTestMixin): # Test for DimCoord.core_points() with various types of points and bounds. - def setUp(self): - self.setupTestArrays() + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_real_points(self): data = self.pts_real coord = DimCoord(data) result = coord.core_points() - self.assertArraysDoNotShareData( + self.assert_arrays_do_not_share_data( result, self.pts_real, "core_points() are the same data as the internal array.", @@ -172,23 +172,24 @@ def test_lazy_points(self): lazy_data = self.pts_lazy coord = DimCoord(lazy_data) result = coord.core_points() - self.assertEqualRealArraysAndDtypes(result, self.pts_real) + self.assert_equal_real_arrays_and_dtypes(result, self.pts_real) -class Test_core_bounds(tests.IrisTest, DimCoordTestMixin): +class Test_core_bounds(DimCoordTestMixin): # Test for DimCoord.core_bounds() with various types of points and bounds. - def setUp(self): - self.setupTestArrays() + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_no_bounds(self): coord = DimCoord(self.pts_real) result = coord.core_bounds() - self.assertIsNone(result) + assert result is None def test_real_bounds(self): coord = DimCoord(self.pts_real, bounds=self.bds_real) result = coord.core_bounds() - self.assertArraysDoNotShareData( + self.assert_arrays_do_not_share_data( result, self.bds_real, "core_bounds() are the same data as the internal array.", @@ -197,100 +198,105 @@ def test_real_bounds(self): def test_lazy_bounds(self): coord = DimCoord(self.pts_real, bounds=self.bds_lazy) result = coord.core_bounds() - self.assertEqualRealArraysAndDtypes(result, self.bds_real) + self.assert_equal_real_arrays_and_dtypes(result, self.bds_real) -class Test_lazy_points(tests.IrisTest, DimCoordTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_lazy_points(DimCoordTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_real_core(self): coord = DimCoord(self.pts_real) result = coord.lazy_points() - self.assertEqualLazyArraysAndDtypes(result, self.pts_lazy) + self.assert_equal_lazy_arrays_and_dtypes(result, self.pts_lazy) def test_lazy_core(self): coord = DimCoord(self.pts_lazy) result = coord.lazy_points() - self.assertEqualLazyArraysAndDtypes(result, self.pts_lazy) + self.assert_equal_lazy_arrays_and_dtypes(result, self.pts_lazy) # NOTE: identity, as in "result is self.pts_lazy" does *NOT* work. -class Test_lazy_bounds(tests.IrisTest, DimCoordTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_lazy_bounds(DimCoordTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_no_bounds(self): coord = DimCoord(self.pts_real) result = coord.lazy_bounds() - self.assertIsNone(result) + assert result is None def test_real_core(self): coord = DimCoord(self.pts_real, bounds=self.bds_real) result = coord.lazy_bounds() - self.assertEqualLazyArraysAndDtypes(result, self.bds_lazy) + self.assert_equal_lazy_arrays_and_dtypes(result, self.bds_lazy) def test_lazy_core(self): coord = DimCoord(self.pts_real, bounds=self.bds_lazy) result = coord.lazy_bounds() - self.assertEqualLazyArraysAndDtypes(result, self.bds_lazy) + self.assert_equal_lazy_arrays_and_dtypes(result, self.bds_lazy) # NOTE: identity, as in "result is self.bds_lazy" does *NOT* work. -class Test_has_lazy_points(tests.IrisTest, DimCoordTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_has_lazy_points(DimCoordTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_real_core(self): coord = DimCoord(self.pts_real) result = coord.has_lazy_points() - self.assertFalse(result) + assert not result def test_lazy_core(self): coord = DimCoord(self.pts_lazy) result = coord.has_lazy_points() - self.assertFalse(result) + assert not result -class Test_has_lazy_bounds(tests.IrisTest, DimCoordTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_has_lazy_bounds(DimCoordTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_real_core(self): coord = DimCoord(self.pts_real, bounds=self.bds_real) result = coord.has_lazy_bounds() - self.assertFalse(result) + assert not result def test_lazy_core(self): coord = DimCoord(self.pts_real, bounds=self.bds_lazy) result = coord.has_lazy_bounds() - self.assertFalse(result) + assert not result -class Test_bounds_dtype(tests.IrisTest): +class Test_bounds_dtype: def test_i16(self): test_dtype = np.int16 coord = DimCoord([1], bounds=np.array([[0, 4]], dtype=test_dtype)) result = coord.bounds_dtype - self.assertEqual(result, test_dtype) + assert result == test_dtype def test_u16(self): test_dtype = np.uint16 coord = DimCoord([1], bounds=np.array([[0, 4]], dtype=test_dtype)) result = coord.bounds_dtype - self.assertEqual(result, test_dtype) + assert result == test_dtype def test_f16(self): test_dtype = np.float16 coord = DimCoord([1], bounds=np.array([[0, 4]], dtype=test_dtype)) result = coord.bounds_dtype - self.assertEqual(result, test_dtype) + assert result == test_dtype -class Test__getitem__(tests.IrisTest, DimCoordTestMixin): +class Test__getitem__(DimCoordTestMixin): # Test for DimCoord indexing with various types of points and bounds. - def setUp(self): - self.setupTestArrays() + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_dtypes(self): # Index coords with all combinations of real+lazy points+bounds, and @@ -312,31 +318,23 @@ def test_dtypes(self): ) sub_points = sub_coord.core_points() - self.assertEqual( - sub_points.dtype, + assert sub_points.dtype == coord_dtype, msg.format( coord_dtype, - msg.format( - coord_dtype, - points_type_name, - bounds_type_name, - "points", - sub_points.dtype, - ), + points_type_name, + bounds_type_name, + "points", + sub_points.dtype, ) if bounds_type_name != "no": sub_bounds = sub_coord.core_bounds() main_bounds_dtype = main_coord.bounds_dtype - self.assertEqual( - sub_bounds.dtype, + assert sub_bounds.dtype == main_bounds_dtype, msg.format( main_bounds_dtype, - msg.format( - main_bounds_dtype, - points_type_name, - bounds_type_name, - "bounds", - sub_bounds.dtype, - ), + points_type_name, + bounds_type_name, + "bounds", + sub_bounds.dtype, ) def test_lazyness(self): @@ -365,32 +363,24 @@ def test_lazyness(self): ) coord_dtype = main_coord.dtype sub_points_lazyness = lazyness_string(sub_coord.core_points()) - self.assertEqual( - sub_points_lazyness, + assert sub_points_lazyness == points_type_name, msg.format( + coord_dtype, points_type_name, - msg.format( - coord_dtype, - points_type_name, - bounds_type_name, - "points", - points_type_name, - sub_points_lazyness, - ), + bounds_type_name, + "points", + points_type_name, + sub_points_lazyness, ) if bounds_type_name != "no": sub_bounds_lazy = lazyness_string(sub_coord.core_bounds()) - self.assertEqual( - sub_bounds_lazy, + assert sub_bounds_lazy == bounds_type_name, msg.format( + coord_dtype, + points_type_name, + bounds_type_name, + "bounds", bounds_type_name, - msg.format( - coord_dtype, - points_type_name, - bounds_type_name, - "bounds", - bounds_type_name, - sub_bounds_lazy, - ), + sub_bounds_lazy, ) def test_real_data_copies(self): @@ -411,8 +401,8 @@ def test_real_data_copies(self): main_points = main_coord.core_points() sub_points = sub_coord.core_points() sub_main_points = main_points[:2] - self.assertEqualRealArraysAndDtypes(sub_points, sub_main_points) - self.assertArraysDoNotShareData( + self.assert_equal_real_arrays_and_dtypes(sub_points, sub_main_points) + self.assert_arrays_do_not_share_data( sub_points, sub_main_points, msg.format(points_lazyness, bounds_lazyness, "points"), @@ -422,34 +412,35 @@ def test_real_data_copies(self): main_bounds = main_coord.core_bounds() sub_bounds = sub_coord.core_bounds() sub_main_bounds = main_bounds[:2] - self.assertEqualRealArraysAndDtypes(sub_bounds, sub_main_bounds) - self.assertArraysDoNotShareData( + self.assert_equal_real_arrays_and_dtypes(sub_bounds, sub_main_bounds) + self.assert_arrays_do_not_share_data( sub_bounds, sub_main_bounds, msg.format(points_lazyness, bounds_lazyness, "bounds"), ) -class Test_copy(tests.IrisTest, DimCoordTestMixin): +class Test_copy(DimCoordTestMixin): # Test for DimCoord.copy() with various types of points and bounds. - def setUp(self): - self.setupTestArrays() + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_writable_points(self): coord1 = DimCoord(np.arange(5), bounds=[[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]) coord2 = coord1.copy() msg = "destination is read-only" - with self.assertRaisesRegex(ValueError, msg): + with pytest.raises(ValueError, match=msg): coord1.points[:] = 0 - with self.assertRaisesRegex(ValueError, msg): + with pytest.raises(ValueError, match=msg): coord2.points[:] = 0 - with self.assertRaisesRegex(ValueError, msg): + with pytest.raises(ValueError, match=msg): coord1.bounds[:] = 0 - with self.assertRaisesRegex(ValueError, msg): + with pytest.raises(ValueError, match=msg): coord2.bounds[:] = 0 def test_realdata_readonly(self): @@ -464,33 +455,35 @@ def test_realdata_readonly(self): copied_points = copied_coord.core_points() expected_error_msg = "output array is read-only" - with self.assertRaisesRegex(ValueError, expected_error_msg): + with pytest.raises(ValueError, match=expected_error_msg): copied_points[:1] += 33 if bounds_type_name != "no": copied_bounds = copied_coord.core_bounds() - with self.assertRaisesRegex(ValueError, expected_error_msg): + with pytest.raises(ValueError, match=expected_error_msg): copied_bounds[:1] += 33 -class Test_points__getter(tests.IrisTest, DimCoordTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_points__getter(DimCoordTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_real_points(self): # Getting real points returns a copy coord = DimCoord(self.pts_real) result = coord.core_points() - self.assertArraysDoNotShareData( + self.assert_arrays_do_not_share_data( result, self.pts_real, "Points are the same array as the provided data.", ) -class Test_points__setter(tests.IrisTest, DimCoordTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_points__setter(DimCoordTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_set_real(self): # Setting points copies the data @@ -498,7 +491,7 @@ def test_set_real(self): new_pts = self.pts_real + 102.3 coord.points = new_pts result = coord.core_points() - self.assertArraysDoNotShareData( + self.assert_arrays_do_not_share_data( result, new_pts, "Points are the same data as the assigned array." ) @@ -507,17 +500,17 @@ def test_fail_bad_shape(self): points = [1.0, 2.0] coord = DimCoord(points) msg = r"Require data with shape \(2,\), got \(3,\)" - with self.assertRaisesRegex(ValueError, msg): + with pytest.raises(ValueError, match=msg): coord.points = np.array([1.0, 2.0, 3.0]) - self.assertArrayEqual(coord.points, points) + _shared_utils.assert_array_equal(coord.points, points) def test_fail_not_monotonic(self): # Setting real points requires that they are monotonic. coord = DimCoord(self.pts_real, bounds=self.bds_real) msg = "strictly monotonic" - with self.assertRaisesRegex(ValueError, msg): + with pytest.raises(ValueError, match=msg): coord.points = np.array([3.0, 1.0, 2.0]) - self.assertArrayEqual(coord.points, self.pts_real) + _shared_utils.assert_array_equal(coord.points, self.pts_real) def test_set_lazy(self): # Setting new lazy points realises them. @@ -525,34 +518,36 @@ def test_set_lazy(self): new_pts = self.pts_lazy + 102.3 coord.points = new_pts result = coord.core_points() - self.assertEqualRealArraysAndDtypes(result, new_pts.compute()) + self.assert_equal_real_arrays_and_dtypes(result, new_pts.compute()) def test_copy_array(self): # Assigning points creates a copy pts = np.array([1, 2, 3]) coord = DimCoord(pts) pts[1] = 5 - self.assertEqual(coord.points[1], 2) + assert coord.points[1] == 2 -class Test_bounds__getter(tests.IrisTest, DimCoordTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_bounds__getter(DimCoordTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_real_bounds(self): # Getting real bounds does not change or copy them. coord = DimCoord(self.pts_real, bounds=self.bds_real) result = coord.bounds - self.assertArraysDoNotShareData( + self.assert_arrays_do_not_share_data( result, self.bds_real, "Bounds are the same array as the provided data.", ) -class Test_bounds__setter(tests.IrisTest, DimCoordTestMixin): - def setUp(self): - self.setupTestArrays() +class Test_bounds__setter(DimCoordTestMixin): + @pytest.fixture(autouse=True) + def _setup(self): + self.setup_test_arrays() def test_set_real(self): # Setting bounds does not copy, but makes a readonly view. @@ -560,7 +555,7 @@ def test_set_real(self): new_bounds = self.bds_real + 102.3 coord.bounds = new_bounds result = coord.core_bounds() - self.assertArraysDoNotShareData( + self.assert_arrays_do_not_share_data( result, new_bounds, "Bounds are the same data as the assigned array.", @@ -570,17 +565,17 @@ def test_fail_bad_shape(self): # Setting real points requires matching shape. coord = DimCoord(self.pts_real, bounds=self.bds_real) msg = "The shape of the 'unknown' DimCoord bounds array should be" - with self.assertRaisesRegex(ValueError, msg): + with pytest.raises(ValueError, match=msg): coord.bounds = np.array([1.0, 2.0, 3.0]) - self.assertArrayEqual(coord.bounds, self.bds_real) + _shared_utils.assert_array_equal(coord.bounds, self.bds_real) def test_fail_not_monotonic(self): # Setting real bounds requires that they are monotonic. coord = DimCoord(self.pts_real, bounds=self.bds_real) msg = "strictly monotonic" - with self.assertRaisesRegex(ValueError, msg): + with pytest.raises(ValueError, match=msg): coord.bounds = np.array([[3.0, 2.0], [1.0, 0.0], [2.0, 1.0]]) - self.assertArrayEqual(coord.bounds, self.bds_real) + _shared_utils.assert_array_equal(coord.bounds, self.bds_real) def test_set_lazy(self): # Setting new lazy bounds realises them. @@ -588,7 +583,7 @@ def test_set_lazy(self): new_bounds = self.bds_lazy + 102.3 coord.bounds = new_bounds result = coord.core_bounds() - self.assertEqualRealArraysAndDtypes(result, new_bounds.compute()) + self.assert_equal_real_arrays_and_dtypes(result, new_bounds.compute()) def test_copy_array(self): # Assigning bounds creates a copy @@ -596,20 +591,16 @@ def test_copy_array(self): bnds = np.array([[1, 3], [3, 5], [5, 7]]) coord = DimCoord(pts, bounds=bnds) bnds[1, 1] = 10 - self.assertEqual(coord.bounds[1, 1], 5) + assert coord.bounds[1, 1] == 5 def test_flip_contiguous(self): pts = np.arange(4) bnds = np.transpose([np.arange(1, 5), np.arange(4)]) coord = DimCoord(pts, bounds=bnds) - self.assertArrayEqual(coord.bounds, bnds[:, ::-1]) + _shared_utils.assert_array_equal(coord.bounds, bnds[:, ::-1]) def test_flip_contiguous_decreasing(self): pts = np.arange(4, 0, -1) bnds = np.transpose([np.arange(4, 0, -1), np.arange(5, 1, -1)]) coord = DimCoord(pts, bounds=bnds) - self.assertArrayEqual(coord.bounds, bnds[:, ::-1]) - - -if __name__ == "__main__": - tests.main() + _shared_utils.assert_array_equal(coord.bounds, bnds[:, ::-1])