diff --git a/lib/iris/tests/unit/fileformats/__init__.py b/lib/iris/tests/unit/fileformats/__init__.py index 81e6c8cedf..c5982fc475 100644 --- a/lib/iris/tests/unit/fileformats/__init__.py +++ b/lib/iris/tests/unit/fileformats/__init__.py @@ -3,63 +3,3 @@ # This file is part of Iris and is released under the BSD license. # See LICENSE in the root of the repository for full licensing details. """Unit tests for the :mod:`iris.fileformats` package.""" - -import iris.tests as tests # isort:skip - - -class TestField(tests.IrisTest): - def _test_for_coord( - self, field, convert, coord_predicate, expected_points, expected_bounds - ): - ( - factories, - references, - standard_name, - long_name, - units, - attributes, - cell_methods, - dim_coords_and_dims, - aux_coords_and_dims, - ) = convert(field) - - # Check for one and only one matching coordinate. - coords_and_dims = dim_coords_and_dims + aux_coords_and_dims - matching_coords = [ - coord for coord, _ in coords_and_dims if coord_predicate(coord) - ] - self.assertEqual(len(matching_coords), 1, str(matching_coords)) - coord = matching_coords[0] - - # Check points and bounds. - if expected_points is not None: - self.assertArrayEqual(coord.points, expected_points) - - if expected_bounds is None: - self.assertIsNone(coord.bounds) - else: - self.assertArrayEqual(coord.bounds, expected_bounds) - - def assertCoordsAndDimsListsMatch( - self, coords_and_dims_got, coords_and_dims_expected - ): - """Check that coords_and_dims lists are equivalent. - - The arguments are lists of pairs of (coordinate, dimensions). - The elements are compared one-to-one, by coordinate name (so the order - of the lists is _not_ significant). - It also checks that the coordinate types (DimCoord/AuxCoord) match. - - """ - - def sorted_by_coordname(list): - return sorted(list, key=lambda item: item[0].name()) - - coords_and_dims_got = sorted_by_coordname(coords_and_dims_got) - coords_and_dims_expected = sorted_by_coordname(coords_and_dims_expected) - self.assertEqual(coords_and_dims_got, coords_and_dims_expected) - # Also check coordinate type equivalences (as Coord.__eq__ does not). - self.assertEqual( - [type(coord) for coord, dims in coords_and_dims_got], - [type(coord) for coord, dims in coords_and_dims_expected], - ) diff --git a/lib/iris/tests/unit/fileformats/pp_load_rules/__init__.py b/lib/iris/tests/unit/fileformats/pp_load_rules/__init__.py index c8361feae4..dd6485b015 100644 --- a/lib/iris/tests/unit/fileformats/pp_load_rules/__init__.py +++ b/lib/iris/tests/unit/fileformats/pp_load_rules/__init__.py @@ -3,3 +3,26 @@ # This file is part of Iris and is released under the BSD license. # See LICENSE in the root of the repository for full licensing details. """Unit tests for the :mod:`iris.fileformats.pp_load_rules` module.""" + + +# a general utility function for PP field tests +def assert_coords_and_dims_lists_match(coords_and_dims_got, coords_and_dims_expected): + """Check that coords_and_dims lists are equivalent. + + The arguments are lists of pairs of (coordinate, dimensions). + The elements are compared one-to-one, by coordinate name (so the order + of the lists is _not_ significant). + It also checks that the coordinate types (DimCoord/AuxCoord) match. + + """ + + def sorted_by_coordname(list): + return sorted(list, key=lambda item: item[0].name()) + + coords_and_dims_got = sorted_by_coordname(coords_and_dims_got) + coords_and_dims_expected = sorted_by_coordname(coords_and_dims_expected) + assert coords_and_dims_got == coords_and_dims_expected + # Also check coordinate type equivalences (as Coord.__eq__ does not). + assert [type(coord) for coord, dims in coords_and_dims_got] == [ + type(coord) for coord, dims in coords_and_dims_expected + ] diff --git a/lib/iris/tests/unit/fileformats/pp_load_rules/test__all_other_rules.py b/lib/iris/tests/unit/fileformats/pp_load_rules/test__all_other_rules.py index aa6b79e9a0..9fdc96abf1 100644 --- a/lib/iris/tests/unit/fileformats/pp_load_rules/test__all_other_rules.py +++ b/lib/iris/tests/unit/fileformats/pp_load_rules/test__all_other_rules.py @@ -3,11 +3,6 @@ # This file is part of Iris and is released under the BSD license. # See LICENSE in the root of the repository for full licensing details. """Unit tests for the `iris.fileformats.pp_load_rules._all_other_rules` function.""" - -# 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 CALENDAR_360_DAY, Unit @@ -17,7 +12,7 @@ from iris.coords import AuxCoord, CellMethod, DimCoord from iris.fileformats.pp import SplittableInt from iris.fileformats.pp_load_rules import _all_other_rules -from iris.tests.unit.fileformats import TestField +from iris.tests.unit.fileformats.pp_load_rules import assert_coords_and_dims_lists_match # iris.fileformats.pp_load_rules._all_other_rules() returns a tuple of # of various metadata. This constant is the index into this @@ -27,88 +22,88 @@ AUX_COORDS_INDEX = 7 -class TestCellMethods(tests.IrisTest): - def test_time_mean(self): +class TestCellMethods: + def test_time_mean(self, mocker): # lbproc = 128 -> mean # lbtim.ib = 2 -> simple t1 to t2 interval. - field = mock.MagicMock(lbproc=128, lbtim=mock.Mock(ia=0, ib=2, ic=3)) + field = mocker.MagicMock(lbproc=128, lbtim=mocker.Mock(ia=0, ib=2, ic=3)) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [CellMethod("mean", "time")] - self.assertEqual(res, expected) + assert res == expected - def test_hourly_mean(self): + def test_hourly_mean(self, mocker): # lbtim.ia = 1 -> hourly - field = mock.MagicMock(lbproc=128, lbtim=mock.Mock(ia=1, ib=2, ic=3)) + field = mocker.MagicMock(lbproc=128, lbtim=mocker.Mock(ia=1, ib=2, ic=3)) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [CellMethod("mean", "time", "1 hour")] - self.assertEqual(res, expected) + assert res == expected - def test_daily_mean(self): + def test_daily_mean(self, mocker): # lbtim.ia = 24 -> daily - field = mock.MagicMock(lbproc=128, lbtim=mock.Mock(ia=24, ib=2, ic=3)) + field = mocker.MagicMock(lbproc=128, lbtim=mocker.Mock(ia=24, ib=2, ic=3)) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [CellMethod("mean", "time", "24 hour")] - self.assertEqual(res, expected) + assert res == expected - def test_custom_max(self): - field = mock.MagicMock(lbproc=8192, lbtim=mock.Mock(ia=47, ib=2, ic=3)) + def test_custom_max(self, mocker): + field = mocker.MagicMock(lbproc=8192, lbtim=mocker.Mock(ia=47, ib=2, ic=3)) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [CellMethod("maximum", "time", "47 hour")] - self.assertEqual(res, expected) + assert res == expected - def test_daily_min(self): + def test_daily_min(self, mocker): # lbproc = 4096 -> min - field = mock.MagicMock(lbproc=4096, lbtim=mock.Mock(ia=24, ib=2, ic=3)) + field = mocker.MagicMock(lbproc=4096, lbtim=mocker.Mock(ia=24, ib=2, ic=3)) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [CellMethod("minimum", "time", "24 hour")] - self.assertEqual(res, expected) + assert res == expected - def test_time_mean_over_multiple_years(self): + def test_time_mean_over_multiple_years(self, mocker): # lbtim.ib = 3 -> interval within a year, over multiple years. - field = mock.MagicMock(lbproc=128, lbtim=mock.Mock(ia=0, ib=3, ic=3)) + field = mocker.MagicMock(lbproc=128, lbtim=mocker.Mock(ia=0, ib=3, ic=3)) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [ CellMethod("mean within years", "time"), CellMethod("mean over years", "time"), ] - self.assertEqual(res, expected) + assert res == expected - def test_hourly_mean_over_multiple_years(self): - field = mock.MagicMock(lbproc=128, lbtim=mock.Mock(ia=1, ib=3, ic=3)) + def test_hourly_mean_over_multiple_years(self, mocker): + field = mocker.MagicMock(lbproc=128, lbtim=mocker.Mock(ia=1, ib=3, ic=3)) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [ CellMethod("mean within years", "time", "1 hour"), CellMethod("mean over years", "time"), ] - self.assertEqual(res, expected) + assert res == expected - def test_climatology_max(self): - field = mock.MagicMock(lbproc=8192, lbtim=mock.Mock(ia=24, ib=3, ic=3)) + def test_climatology_max(self, mocker): + field = mocker.MagicMock(lbproc=8192, lbtim=mocker.Mock(ia=24, ib=3, ic=3)) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [CellMethod("maximum", "time")] - self.assertEqual(res, expected) + assert res == expected - def test_climatology_min(self): - field = mock.MagicMock(lbproc=4096, lbtim=mock.Mock(ia=24, ib=3, ic=3)) + def test_climatology_min(self, mocker): + field = mocker.MagicMock(lbproc=4096, lbtim=mocker.Mock(ia=24, ib=3, ic=3)) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [CellMethod("minimum", "time")] - self.assertEqual(res, expected) + assert res == expected - def test_other_lbtim_ib(self): + def test_other_lbtim_ib(self, mocker): # lbtim.ib = 5 -> non-specific aggregation - field = mock.MagicMock(lbproc=4096, lbtim=mock.Mock(ia=24, ib=5, ic=3)) + field = mocker.MagicMock(lbproc=4096, lbtim=mocker.Mock(ia=24, ib=5, ic=3)) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [CellMethod("minimum", "time")] - self.assertEqual(res, expected) + assert res == expected - def test_multiple_unordered_lbprocs(self): - field = mock.MagicMock( + def test_multiple_unordered_lbprocs(self, mocker): + field = mocker.MagicMock( lbproc=192, bzx=0, bdx=1, lbnpt=3, lbrow=3, - lbtim=mock.Mock(ia=24, ib=5, ic=3), + lbtim=mocker.Mock(ia=24, ib=5, ic=3), lbcode=SplittableInt(1), x_bounds=None, _x_coord_name=lambda: "longitude", @@ -119,16 +114,16 @@ def test_multiple_unordered_lbprocs(self): CellMethod("mean", "time"), CellMethod("mean", "longitude"), ] - self.assertEqual(res, expected) + assert res == expected - def test_multiple_unordered_rotated_lbprocs(self): - field = mock.MagicMock( + def test_multiple_unordered_rotated_lbprocs(self, mocker): + field = mocker.MagicMock( lbproc=192, bzx=0, bdx=1, lbnpt=3, lbrow=3, - lbtim=mock.Mock(ia=24, ib=5, ic=3), + lbtim=mocker.Mock(ia=24, ib=5, ic=3), lbcode=SplittableInt(101), x_bounds=None, _x_coord_name=lambda: "grid_longitude", @@ -139,15 +134,15 @@ def test_multiple_unordered_rotated_lbprocs(self): CellMethod("mean", "time"), CellMethod("mean", "grid_longitude"), ] - self.assertEqual(res, expected) + assert res == expected -class TestCrossSectionalTime(TestField): - def test_lbcode3x23(self): +class TestCrossSectionalTime: + def test_lbcode3x23(self, mocker): time_bounds = np.array( [[0.875, 1.125], [1.125, 1.375], [1.375, 1.625], [1.625, 1.875]] ) - field = mock.MagicMock( + field = mocker.MagicMock( lbproc=0, bzx=0, bdx=0, @@ -155,7 +150,7 @@ def test_lbcode3x23(self): lbrow=4, t1=nc_datetime(2000, 1, 2, hour=0, minute=0, second=0), t2=nc_datetime(2000, 1, 3, hour=0, minute=0, second=0), - lbtim=mock.Mock(ia=1, ib=2, ic=2), + lbtim=mocker.Mock(ia=1, ib=2, ic=2), lbcode=SplittableInt(31323, {"iy": slice(0, 2), "ix": slice(2, 4)}), x_bounds=None, y_bounds=time_bounds, @@ -201,10 +196,10 @@ def test_lbcode3x23(self): 0, ) ] - self.assertCoordsAndDimsListsMatch(res, expected) + assert_coords_and_dims_lists_match(res, expected) -class TestLBTIMx2x_ZeroYears(TestField): +class TestLBTIMx2x_ZeroYears: _spec = [ "lbtim", "lbcode", @@ -272,29 +267,25 @@ def test_month_coord(self): None, ), ] - self.assertCoordsAndDimsListsMatch(res, expected) + assert_coords_and_dims_lists_match(res, expected) def test_diff_month(self): field = self._make_field(lbmon=3, lbmond=4) field.mock_add_spec(self._spec) res = _all_other_rules(field)[AUX_COORDS_INDEX] - self.assertCoordsAndDimsListsMatch(res, []) + assert_coords_and_dims_lists_match(res, []) def test_nonzero_year(self): field = self._make_field(lbyr=1) field.mock_add_spec(self._spec) res = _all_other_rules(field)[AUX_COORDS_INDEX] - self.assertCoordsAndDimsListsMatch(res, []) + assert_coords_and_dims_lists_match(res, []) def test_nonzero_yeard(self): field = self._make_field(lbyrd=1) field.mock_add_spec(self._spec) res = _all_other_rules(field)[AUX_COORDS_INDEX] - self.assertCoordsAndDimsListsMatch(res, []) - - -if __name__ == "__main__": - tests.main() + assert_coords_and_dims_lists_match(res, []) diff --git a/lib/iris/tests/unit/fileformats/pp_load_rules/test__collapse_degenerate_points_and_bounds.py b/lib/iris/tests/unit/fileformats/pp_load_rules/test__collapse_degenerate_points_and_bounds.py index 7d502bc2d6..e666ae2d9a 100644 --- a/lib/iris/tests/unit/fileformats/pp_load_rules/test__collapse_degenerate_points_and_bounds.py +++ b/lib/iris/tests/unit/fileformats/pp_load_rules/test__collapse_degenerate_points_and_bounds.py @@ -6,57 +6,53 @@ :func:`iris.fileformats.pp_load_rules._collapse_degenerate_points_and_bounds`. """ - -# 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 from iris.fileformats.pp_load_rules import _collapse_degenerate_points_and_bounds +from iris.tests._shared_utils import assert_array_equal -class Test(tests.IrisTest): +class Test: def test_scalar(self): array = np.array(1) points, bounds = _collapse_degenerate_points_and_bounds(array) - self.assertArrayEqual(points, array) - self.assertIsNone(bounds) + assert_array_equal(points, array) + assert bounds is None def test_1d_nochange(self): array = np.array([1, 1, 3]) result, _ = _collapse_degenerate_points_and_bounds(array) - self.assertArrayEqual(result, array) + assert_array_equal(result, array) def test_1d_collapse(self): array = np.array([1, 1, 1]) result, _ = _collapse_degenerate_points_and_bounds(array) - self.assertArrayEqual(result, np.array([1])) + assert_array_equal(result, np.array([1])) def test_2d_nochange(self): array = np.array([[1, 2, 3], [4, 5, 6]]) result, _ = _collapse_degenerate_points_and_bounds(array) - self.assertArrayEqual(result, array) + assert_array_equal(result, array) def test_2d_collapse_dim0(self): array = np.array([[1, 2, 3], [1, 2, 3]]) result, _ = _collapse_degenerate_points_and_bounds(array) - self.assertArrayEqual(result, np.array([[1, 2, 3]])) + assert_array_equal(result, np.array([[1, 2, 3]])) def test_2d_collapse_dim1(self): array = np.array([[1, 1, 1], [2, 2, 2]]) result, _ = _collapse_degenerate_points_and_bounds(array) - self.assertArrayEqual(result, np.array([[1], [2]])) + assert_array_equal(result, np.array([[1], [2]])) def test_2d_collapse_both(self): array = np.array([[3, 3, 3], [3, 3, 3]]) result, _ = _collapse_degenerate_points_and_bounds(array) - self.assertArrayEqual(result, np.array([[3]])) + assert_array_equal(result, np.array([[3]])) def test_3d(self): array = np.array([[[3, 3, 3], [4, 4, 4]], [[3, 3, 3], [4, 4, 4]]]) result, _ = _collapse_degenerate_points_and_bounds(array) - self.assertArrayEqual(result, np.array([[[3], [4]]])) + assert_array_equal(result, np.array([[[3], [4]]])) def test_multiple_odd_dims(self): # Test to ensure multiple collapsed dimensions don't interfere. @@ -66,24 +62,20 @@ def test_multiple_odd_dims(self): array[:, :, 1:] = array[:, :, 0:1] array[:, :, :, 1:] = array[:, :, :, 0:1] result, _ = _collapse_degenerate_points_and_bounds(array) - self.assertEqual(array.shape, (3, 3, 3, 3, 3)) - self.assertEqual(result.shape, (1, 3, 1, 1, 3)) - self.assertTrue(np.all(result == array[0:1, :, 0:1, 0:1, :])) + assert array.shape == (3, 3, 3, 3, 3) + assert result.shape == (1, 3, 1, 1, 3) + assert np.all(result == array[0:1, :, 0:1, 0:1, :]) def test_bounds_collapse(self): points = np.array([1, 1, 1]) bounds = np.array([[0, 1], [0, 1], [0, 1]]) result_pts, result_bds = _collapse_degenerate_points_and_bounds(points, bounds) - self.assertArrayEqual(result_pts, np.array([1])) - self.assertArrayEqual(result_bds, np.array([[0, 1]])) + assert_array_equal(result_pts, np.array([1])) + assert_array_equal(result_bds, np.array([[0, 1]])) def test_bounds_no_collapse(self): points = np.array([1, 1, 1]) bounds = np.array([[0, 1], [0, 1], [0, 2]]) result_pts, result_bds = _collapse_degenerate_points_and_bounds(points, bounds) - self.assertArrayEqual(result_pts, points) - self.assertArrayEqual(result_bds, bounds) - - -if __name__ == "__main__": - tests.main() + assert_array_equal(result_pts, points) + assert_array_equal(result_bds, bounds) diff --git a/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_scalar_pseudo_level_coords.py b/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_scalar_pseudo_level_coords.py index bc3cf8ed86..978097e8ee 100644 --- a/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_scalar_pseudo_level_coords.py +++ b/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_scalar_pseudo_level_coords.py @@ -6,28 +6,17 @@ :func:`iris.fileformats.pp_load_rules._convert_pseudo_level_coords`. """ - -# Import iris.tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests # isort:skip - from iris.coords import DimCoord from iris.fileformats.pp_load_rules import _convert_scalar_pseudo_level_coords -from iris.tests.unit.fileformats import TestField -class Test(TestField): +class Test: def test_valid(self): coords_and_dims = _convert_scalar_pseudo_level_coords(lbuser5=21) - self.assertEqual( - coords_and_dims, - [(DimCoord([21], long_name="pseudo_level", units="1"), None)], - ) + assert coords_and_dims == [ + (DimCoord([21], long_name="pseudo_level", units="1"), None) + ] def test_missing_indicator(self): coords_and_dims = _convert_scalar_pseudo_level_coords(lbuser5=0) - self.assertEqual(coords_and_dims, []) - - -if __name__ == "__main__": - tests.main() + assert coords_and_dims == [] diff --git a/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_scalar_realization_coords.py b/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_scalar_realization_coords.py index ac28fe0a1c..c00c4c1b5d 100644 --- a/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_scalar_realization_coords.py +++ b/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_scalar_realization_coords.py @@ -6,28 +6,17 @@ :func:`iris.fileformats.pp_load_rules._convert_scalar_realization_coords`. """ - -# Import iris.tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests # isort:skip - from iris.coords import DimCoord from iris.fileformats.pp_load_rules import _convert_scalar_realization_coords -from iris.tests.unit.fileformats import TestField -class Test(TestField): +class Test: def test_valid(self): coords_and_dims = _convert_scalar_realization_coords(lbrsvd4=21) - self.assertEqual( - coords_and_dims, - [(DimCoord([21], standard_name="realization", units="1"), None)], - ) + assert coords_and_dims == [ + (DimCoord([21], standard_name="realization", units="1"), None) + ] def test_missing_indicator(self): coords_and_dims = _convert_scalar_realization_coords(lbrsvd4=0) - self.assertEqual(coords_and_dims, []) - - -if __name__ == "__main__": - tests.main() + assert coords_and_dims == [] diff --git a/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_time_coords.py b/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_time_coords.py index 5cebc009b9..a7656a8ec6 100644 --- a/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_time_coords.py +++ b/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_time_coords.py @@ -6,11 +6,6 @@ :func:`iris.fileformats.pp_load_rules._convert_time_coords`. """ - -# 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 CALENDAR_360_DAY, CALENDAR_STANDARD, Unit from cftime import datetime as nc_datetime import numpy as np @@ -18,7 +13,8 @@ from iris.coords import AuxCoord, DimCoord from iris.fileformats.pp import SplittableInt from iris.fileformats.pp_load_rules import _convert_time_coords -from iris.tests.unit.fileformats import TestField +from iris.tests._shared_utils import assert_array_all_close +from iris.tests.unit.fileformats.pp_load_rules import assert_coords_and_dims_lists_match def _lbtim(ia=0, ib=0, ic=0): @@ -40,7 +36,7 @@ def _lbcode(value=None, ix=None, iy=None): _HOURS_UNIT = Unit("hours") -class TestLBTIMx0x_SingleTimepoint(TestField): +class TestLBTIMx0x_SingleTimepoint: def _check_timepoint(self, lbcode, expect_match=True): lbtim = _lbtim(ib=0, ic=1) t1 = nc_datetime(1970, 1, 1, hour=6, minute=0, second=0) @@ -69,7 +65,7 @@ def _check_timepoint(self, lbcode, expect_match=True): ] else: expect_result = [] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expect_result) + assert_coords_and_dims_lists_match(coords_and_dims, expect_result) def test_normal_xy_dims(self): self._check_timepoint(_lbcode(1)) @@ -81,7 +77,7 @@ def test_time_cross_section(self): self._check_timepoint(_lbcode(ix=1, iy=20), expect_match=False) -class TestLBTIMx1x_Forecast(TestField): +class TestLBTIMx1x_Forecast: def _check_forecast(self, lbcode, expect_match=True): lbtim = _lbtim(ib=1, ic=1) # Validity time @@ -126,7 +122,7 @@ def _check_forecast(self, lbcode, expect_match=True): ] else: expect_result = [] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expect_result) + assert_coords_and_dims_lists_match(coords_and_dims, expect_result) def test_normal_xy(self): self._check_forecast(_lbcode(1)) @@ -151,8 +147,8 @@ def test_exact_hours(self): ) (fp, _), (t, _), (frt, _) = coords_and_dims # These should both be exact whole numbers. - self.assertEqual(fp.points[0], 7) - self.assertEqual(t.points[0], 394927) + assert fp.points[0] == 7 + assert t.points[0] == 394927 def test_not_exact_hours(self): lbtim = _lbtim(ib=1, ic=1) @@ -167,11 +163,11 @@ def test_not_exact_hours(self): lbft=None, ) (fp, _), (t, _), (frt, _) = coords_and_dims - self.assertArrayAllClose(fp.points[0], 7.1666666, atol=0.0001, rtol=0) - self.assertArrayAllClose(t.points[0], 394927.166666, atol=0.01, rtol=0) + assert_array_all_close(fp.points[0], 7.1666666, atol=0.0001, rtol=0) + assert_array_all_close(t.points[0], 394927.166666, atol=0.01, rtol=0) -class TestLBTIMx2x_TimePeriod(TestField): +class TestLBTIMx2x_TimePeriod: def _check_period(self, lbcode, expect_match=True): lbtim = _lbtim(ib=2, ic=1) # Start time @@ -218,7 +214,7 @@ def _check_period(self, lbcode, expect_match=True): ] else: expect_result = [] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expect_result) + assert_coords_and_dims_lists_match(coords_and_dims, expect_result) def test_normal_xy(self): self._check_period(_lbcode(1)) @@ -230,7 +226,7 @@ def test_time_cross_section(self): self._check_period(_lbcode(ix=1, iy=20), expect_match=False) -class TestLBTIMx3x_YearlyAggregation(TestField): +class TestLBTIMx3x_YearlyAggregation: def _check_yearly(self, lbcode, expect_match=True): lbtim = _lbtim(ib=3, ic=1) # Start time @@ -280,7 +276,7 @@ def _check_yearly(self, lbcode, expect_match=True): ] else: expect_result = [] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expect_result) + assert_coords_and_dims_lists_match(coords_and_dims, expect_result) def test_normal_xy(self): self._check_yearly(_lbcode(1)) @@ -292,7 +288,7 @@ def test_time_cross_section(self): self._check_yearly(_lbcode(ix=1, iy=20), expect_match=False) -class TestLBTIMx2x_ZeroYear(TestField): +class TestLBTIMx2x_ZeroYear: def test_(self): lbtim = _lbtim(ib=2, ic=1) t1 = nc_datetime(0, 1, 1, has_year_zero=True) @@ -307,10 +303,10 @@ def test_(self): t2=t2, lbft=lbft, ) - self.assertEqual(coords_and_dims, []) + assert coords_and_dims == [] -class TestLBTIMxxx_Unhandled(TestField): +class TestLBTIMxxx_Unhandled: def test_unrecognised(self): lbtim = _lbtim(ib=4, ic=1) t1 = nc_datetime(0, 0, 0, calendar=None, has_year_zero=True) @@ -325,10 +321,10 @@ def test_unrecognised(self): t2=t2, lbft=lbft, ) - self.assertEqual(coords_and_dims, []) + assert coords_and_dims == [] -class TestLBCODE3xx(TestField): +class TestLBCODE3xx: def test(self): lbcode = _lbcode(value=31323) lbtim = _lbtim(ib=2, ic=2) @@ -355,10 +351,10 @@ def test(self): None, ) ] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expected_result) + assert_coords_and_dims_lists_match(coords_and_dims, expected_result) -class TestArrayInputWithLBTIM_0_0_1(TestField): +class TestArrayInputWithLBTIM_0_0_1: def test_t1_list(self): # lbtim ia = 0, ib = 0, ic = 1 # with a series of times (t1). @@ -387,10 +383,10 @@ def test_t1_list(self): (24 * 8) + 3 + hours, standard_name="time", units=_EPOCH_HOURS_UNIT ) expected = [(time_coord, (0,))] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expected) + assert_coords_and_dims_lists_match(coords_and_dims, expected) -class TestArrayInputWithLBTIM_0_1_1(TestField): +class TestArrayInputWithLBTIM_0_1_1: def test_t1_list_t2_scalar(self): # lbtim ia = 0, ib = 1, ic = 1 # with a single forecast reference time (t2) and a series @@ -436,7 +432,7 @@ def test_t1_list_t2_scalar(self): (time_coord, (0,)), (fref_time_coord, None), ] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expected) + assert_coords_and_dims_lists_match(coords_and_dims, expected) def test_t1_and_t2_list(self): # lbtim ia = 0, ib = 1, ic = 1 @@ -485,7 +481,7 @@ def test_t1_and_t2_list(self): (time_coord, (0,)), (fref_time_coord, None), ] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expected) + assert_coords_and_dims_lists_match(coords_and_dims, expected) def test_t1_and_t2_orthogonal_lists(self): # lbtim ia = 0, ib = 1, ic = 1 @@ -532,7 +528,7 @@ def test_t1_and_t2_orthogonal_lists(self): (time_coord, (0,)), (fref_time_coord, (1,)), ] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expected) + assert_coords_and_dims_lists_match(coords_and_dims, expected) def test_t1_multi_dim_list_t2_scalar(self): # Another case of lbtim ia = 0, ib = 1, ic = 1 but @@ -586,7 +582,7 @@ def test_t1_multi_dim_list_t2_scalar(self): (time_coord, (0, 1)), (fref_time_coord, None), ] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expected) + assert_coords_and_dims_lists_match(coords_and_dims, expected) def test_t1_and_t2_nparrays(self): # lbtim ia = 0, ib = 1, ic = 1 @@ -639,10 +635,10 @@ def test_t1_and_t2_nparrays(self): (time_coord, (0,)), (fref_time_coord, None), ] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expected) + assert_coords_and_dims_lists_match(coords_and_dims, expected) -class TestArrayInputWithLBTIM_0_2_1(TestField): +class TestArrayInputWithLBTIM_0_2_1: def test_t1_list_t2_scalar(self): lbtim = _lbtim(ib=2, ic=1) lbcode = _lbcode(1) @@ -694,10 +690,10 @@ def test_t1_list_t2_scalar(self): (time_coord, (0,)), (fref_time_coord, None), ] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expected) + assert_coords_and_dims_lists_match(coords_and_dims, expected) -class TestArrayInputWithLBTIM_0_3_1(TestField): +class TestArrayInputWithLBTIM_0_3_1: def test_t1_scalar_t2_list(self): lbtim = _lbtim(ib=3, ic=1) lbcode = _lbcode(1) @@ -754,8 +750,4 @@ def test_t1_scalar_t2_list(self): (time_coord, (0,)), (fref_time_coord, (0,)), ] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expected) - - -if __name__ == "__main__": - tests.main() + assert_coords_and_dims_lists_match(coords_and_dims, expected) diff --git a/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_vertical_coords.py b/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_vertical_coords.py index 0e159b254e..0ba86a68b6 100644 --- a/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_vertical_coords.py +++ b/lib/iris/tests/unit/fileformats/pp_load_rules/test__convert_vertical_coords.py @@ -6,18 +6,13 @@ :func:`iris.fileformats.pp_load_rules._convert_vertical_coords`. """ - -# 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 from iris.aux_factory import HybridHeightFactory, HybridPressureFactory from iris.coords import AuxCoord, DimCoord from iris.fileformats.pp import STASH, SplittableInt from iris.fileformats.pp_load_rules import Reference, _convert_vertical_coords -from iris.tests.unit.fileformats import TestField +from iris.tests.unit.fileformats.pp_load_rules import assert_coords_and_dims_lists_match def _lbcode(value=None, ix=None, iy=None): @@ -31,7 +26,7 @@ def _lbcode(value=None, ix=None, iy=None): return result -class TestLBVC001_Height(TestField): +class TestLBVC001_Height: def _check_height( self, blev, @@ -89,8 +84,8 @@ def _check_height( ] else: expect_result = [] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expect_result) - self.assertEqual(factories, []) + assert_coords_and_dims_lists_match(coords_and_dims, expect_result) + assert factories == [] def test_normal_height__present(self): self._check_height(blev=12.3, stash=STASH(1, 1, 1)) @@ -172,7 +167,7 @@ def test_implied_height_10m__vector(self): ) -class TestLBVC002_Depth(TestField): +class TestLBVC002_Depth: def _check_depth( self, lbcode, @@ -248,8 +243,8 @@ def _check_depth( ) else: expect_result = [] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expect_result) - self.assertEqual(factories, []) + assert_coords_and_dims_lists_match(coords_and_dims, expect_result) + assert factories == [] def test_unbounded(self): self._check_depth(_lbcode(1), lblev=23.0, expect_bounds=False) @@ -323,7 +318,7 @@ def test_cross_section__vector(self): ) -class TestLBVC006_SoilLevel(TestField): +class TestLBVC006_SoilLevel: def _check_soil_level(self, lbcode, lblev=12.3, expect_match=True, dim=None): lbvc = 6 stash = STASH(1, 1, 1) @@ -354,8 +349,8 @@ def _check_soil_level(self, lbcode, lblev=12.3, expect_match=True, dim=None): units="1", ) expect_result = [(coord, dim)] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expect_result) - self.assertEqual(factories, []) + assert_coords_and_dims_lists_match(coords_and_dims, expect_result) + assert factories == [] def test_normal(self): self._check_soil_level(_lbcode(0)) @@ -374,7 +369,7 @@ def test_cross_section__vector(self): ) -class TestLBVC006_SoilDepth(TestField): +class TestLBVC006_SoilDepth: def _check_soil_depth( self, lbcode, @@ -410,8 +405,8 @@ def _check_soil_depth( attributes={"positive": "down"}, ) expect_result = [(coord, dim)] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expect_result) - self.assertEqual(factories, []) + assert_coords_and_dims_lists_match(coords_and_dims, expect_result) + assert factories == [] def test_normal(self): self._check_soil_depth(_lbcode(0)) @@ -450,7 +445,7 @@ def test_cross_section__vector(self): ) -class TestLBVC008_Pressure(TestField): +class TestLBVC008_Pressure: def _check_pressure(self, lbcode, blev=250.3, expect_match=True, dim=None): lbvc = 8 stash = STASH(1, 1, 1) @@ -479,8 +474,8 @@ def _check_pressure(self, lbcode, blev=250.3, expect_match=True, dim=None): expect_result = [(DimCoord(blev, long_name="pressure", units="hPa"), dim)] else: expect_result = [] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expect_result) - self.assertEqual(factories, []) + assert_coords_and_dims_lists_match(coords_and_dims, expect_result) + assert factories == [] def test_normal(self): self._check_pressure(_lbcode(0)) @@ -504,7 +499,7 @@ def test_pressure_cross_section__vector(self): self._check_pressure(_lbcode(ix=10, iy=1), blev=blev, dim=1, expect_match=False) -class TestLBVC019_PotentialTemperature(TestField): +class TestLBVC019_PotentialTemperature: def _check_potm(self, lbcode, blev=130.6, expect_match=True, dim=None): lbvc = 19 stash = STASH(1, 1, 1) @@ -543,8 +538,8 @@ def _check_potm(self, lbcode, blev=130.6, expect_match=True, dim=None): ] else: expect_result = [] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expect_result) - self.assertEqual(factories, []) + assert_coords_and_dims_lists_match(coords_and_dims, expect_result) + assert factories == [] def test_normal(self): self._check_potm(_lbcode(0)) @@ -561,7 +556,7 @@ def test_cross_section__vector(self): self._check_potm(_lbcode(ix=10, iy=11), blev=blev, dim=1, expect_match=False) -class TestLBVC009_HybridPressure(TestField): +class TestLBVC009_HybridPressure: def _check( self, lblev=37.0, @@ -638,8 +633,8 @@ def _check( ], ) ] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expect_coords_and_dims) - self.assertEqual(factories, expect_factories) + assert_coords_and_dims_lists_match(coords_and_dims, expect_coords_and_dims) + assert factories == expect_factories def test_normal(self): self._check() @@ -664,7 +659,7 @@ def test_normal__vector(self): ) -class TestLBVC065_HybridHeight(TestField): +class TestLBVC065_HybridHeight: def _check( self, lblev=37.0, @@ -740,8 +735,8 @@ def _check( ], ) ] - self.assertCoordsAndDimsListsMatch(coords_and_dims, expect_coords_and_dims) - self.assertEqual(factories, expect_factories) + assert_coords_and_dims_lists_match(coords_and_dims, expect_coords_and_dims) + assert factories == expect_factories def test_normal(self): self._check() @@ -767,7 +762,7 @@ def test_normal__vector(self): ) -class TestLBVCxxx_Unhandled(TestField): +class TestLBVCxxx_Unhandled: def test_unknown_lbvc(self): lbvc = 999 blev, lblev, bhlev, bhrlev, brsvd1, brsvd2, brlev = ( @@ -793,9 +788,5 @@ def test_unknown_lbvc(self): brsvd2=brsvd2, brlev=brlev, ) - self.assertEqual(coords_and_dims, []) - self.assertEqual(factories, []) - - -if __name__ == "__main__": - tests.main() + assert coords_and_dims == [] + assert factories == [] diff --git a/lib/iris/tests/unit/fileformats/pp_load_rules/test__dim_or_aux.py b/lib/iris/tests/unit/fileformats/pp_load_rules/test__dim_or_aux.py index 176d0a38a1..c532d4243a 100644 --- a/lib/iris/tests/unit/fileformats/pp_load_rules/test__dim_or_aux.py +++ b/lib/iris/tests/unit/fileformats/pp_load_rules/test__dim_or_aux.py @@ -3,17 +3,15 @@ # This file is part of Iris and is released under the BSD license. # See LICENSE in the root of the repository for full licensing details. """Unit tests for :func:`iris.fileformats.pp_load_rules._dim_or_aux`.""" - -# Import iris.tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests # isort:skip +import pytest from iris.coords import AuxCoord, DimCoord from iris.fileformats.pp_load_rules import _dim_or_aux -class Test(tests.IrisTest): - def setUp(self): +class Test: + @pytest.fixture(autouse=True) + def _setup(self): self.mono = list(range(5)) self.non_mono = [0, 1, 3, 2, 4] self.std_name = "depth" @@ -33,7 +31,7 @@ def test_dim_monotonic(self): units=self.units, attributes=self.attr, ) - self.assertEqual(result, expected) + assert result == expected def test_dim_non_monotonic(self): result = _dim_or_aux( @@ -50,8 +48,4 @@ def test_dim_non_monotonic(self): units=self.units, attributes=attr, ) - self.assertEqual(result, expected) - - -if __name__ == "__main__": - tests.main() + assert result == expected diff --git a/lib/iris/tests/unit/fileformats/pp_load_rules/test__epoch_date_hours.py b/lib/iris/tests/unit/fileformats/pp_load_rules/test__epoch_date_hours.py index f2f19d9bb1..6db53bfcc8 100644 --- a/lib/iris/tests/unit/fileformats/pp_load_rules/test__epoch_date_hours.py +++ b/lib/iris/tests/unit/fileformats/pp_load_rules/test__epoch_date_hours.py @@ -6,16 +6,13 @@ :func:`iris.fileformats.pp_load_rules._epoch_date_hours`. """ - -# Import iris.tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests # isort:skip - import cf_units from cf_units import Unit from cftime import datetime as nc_datetime +import pytest from iris.fileformats.pp_load_rules import _epoch_date_hours as epoch_hours_call +from iris.tests._shared_utils import assert_array_all_close # # Run tests for each of the possible calendars from PPfield.calendar(). @@ -24,30 +21,31 @@ # -class TestEpochHours__standard(tests.IrisTest): - def setUp(self): +class TestEpochHours__standard: + @pytest.fixture(autouse=True) + def _setup(self): self.calendar = cf_units.CALENDAR_STANDARD self.hrs_unit = Unit("hours since epoch", calendar=self.calendar) def test_1970_1_1(self): test_date = nc_datetime(1970, 1, 1, calendar=self.calendar) result = epoch_hours_call(self.hrs_unit, test_date) - self.assertEqual(result, 0.0) + assert result == 0.0 def test_ymd_1_1_1(self): test_date = nc_datetime(1, 1, 1, calendar=self.calendar) result = epoch_hours_call(self.hrs_unit, test_date) - self.assertEqual(result, -17259936.0) + assert result == -17259936.0 def test_year_0(self): test_date = nc_datetime(0, 1, 1, calendar=self.calendar, has_year_zero=True) result = epoch_hours_call(self.hrs_unit, test_date) - self.assertEqual(result, -17268720.0) + assert result == -17268720.0 def test_ymd_0_0_0(self): test_date = nc_datetime(0, 0, 0, calendar=None, has_year_zero=True) result = epoch_hours_call(self.hrs_unit, test_date) - self.assertEqual(result, -17269488.0) + assert result == -17269488.0 def test_ymd_0_preserves_timeofday(self): hrs, mins, secs, usecs = (7, 13, 24, 335772) @@ -69,64 +67,66 @@ def test_ymd_0_preserves_timeofday(self): # NOTE: the calculation is only accurate to approx +/- 0.5 seconds # in such a large number of hours -- even 0.1 seconds is too fine. absolute_tolerance = 0.5 / 3600 - self.assertArrayAllClose( + assert_array_all_close( result, -17269488.0 + hours_in_day, rtol=0, atol=absolute_tolerance ) -class TestEpochHours__360day(tests.IrisTest): - def setUp(self): +class TestEpochHours__360day: + @pytest.fixture(autouse=True) + def _setup(self): self.calendar = cf_units.CALENDAR_360_DAY self.hrs_unit = Unit("hours since epoch", calendar=self.calendar) def test_1970_1_1(self): test_date = nc_datetime(1970, 1, 1, calendar=self.calendar) result = epoch_hours_call(self.hrs_unit, test_date) - self.assertEqual(result, 0.0) + assert result == 0.0 def test_ymd_1_1_1(self): test_date = nc_datetime(1, 1, 1, calendar=self.calendar) result = epoch_hours_call(self.hrs_unit, test_date) - self.assertEqual(result, -17012160.0) + assert result == -17012160.0 def test_year_0(self): test_date = nc_datetime(0, 1, 1, calendar=self.calendar, has_year_zero=True) result = epoch_hours_call(self.hrs_unit, test_date) - self.assertEqual(result, -17020800.0) + assert result == -17020800.0 def test_ymd_0_0_0(self): test_date = nc_datetime(0, 0, 0, calendar=None, has_year_zero=True) result = epoch_hours_call(self.hrs_unit, test_date) - self.assertEqual(result, -17021544.0) + assert result == -17021544.0 -class TestEpochHours__365day(tests.IrisTest): - def setUp(self): +class TestEpochHours__365day: + @pytest.fixture(autouse=True) + def _setup(self): self.calendar = cf_units.CALENDAR_365_DAY self.hrs_unit = Unit("hours since epoch", calendar=self.calendar) def test_1970_1_1(self): test_date = nc_datetime(1970, 1, 1, calendar=self.calendar) result = epoch_hours_call(self.hrs_unit, test_date) - self.assertEqual(result, 0.0) + assert result == 0.0 def test_ymd_1_1_1(self): test_date = nc_datetime(1, 1, 1, calendar=self.calendar) result = epoch_hours_call(self.hrs_unit, test_date) - self.assertEqual(result, -17248440.0) + assert result == -17248440.0 def test_year_0(self): test_date = nc_datetime(0, 1, 1, calendar=self.calendar, has_year_zero=True) result = epoch_hours_call(self.hrs_unit, test_date) - self.assertEqual(result, -17257200.0) + assert result == -17257200.0 def test_ymd_0_0_0(self): test_date = nc_datetime(0, 0, 0, calendar=None, has_year_zero=True) result = epoch_hours_call(self.hrs_unit, test_date) - self.assertEqual(result, -17257968.0) + assert result == -17257968.0 -class TestEpochHours__invalid_calendar(tests.IrisTest): +class TestEpochHours__invalid_calendar: def test_bad_calendar(self): self.calendar = cf_units.CALENDAR_ALL_LEAP # Setup a unit with an unrecognised calendar @@ -134,9 +134,5 @@ def test_bad_calendar(self): # Test against a date with year=0, which requires calendar correction. test_date = nc_datetime(0, 1, 1, calendar=self.calendar, has_year_zero=True) # Check that this causes an error. - with self.assertRaisesRegex(ValueError, "unrecognised calendar"): + with pytest.raises(ValueError, match="unrecognised calendar"): epoch_hours_call(hrs_unit, test_date) - - -if __name__ == "__main__": - tests.main() diff --git a/lib/iris/tests/unit/fileformats/pp_load_rules/test__model_level_number.py b/lib/iris/tests/unit/fileformats/pp_load_rules/test__model_level_number.py index 65c6bc8442..cff13616d6 100644 --- a/lib/iris/tests/unit/fileformats/pp_load_rules/test__model_level_number.py +++ b/lib/iris/tests/unit/fileformats/pp_load_rules/test__model_level_number.py @@ -3,24 +3,15 @@ # This file is part of Iris and is released under the BSD license. # See LICENSE in the root of the repository for full licensing details. """Unit tests for :func:`iris.fileformats.pp_load_rules._model_level_number`.""" - -# Import iris.tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests # isort:skip - from iris.fileformats.pp_load_rules import _model_level_number -class Test_9999(tests.IrisTest): +class Test_9999: def test(self): - self.assertEqual(_model_level_number(9999), 0) + assert _model_level_number(9999) == 0 -class Test_lblev(tests.IrisTest): +class Test_lblev: def test(self): for val in range(9999): - self.assertEqual(_model_level_number(val), val) - - -if __name__ == "__main__": - tests.main() + assert _model_level_number(val) == val diff --git a/lib/iris/tests/unit/fileformats/pp_load_rules/test__reduced_points_and_bounds.py b/lib/iris/tests/unit/fileformats/pp_load_rules/test__reduced_points_and_bounds.py index 6dfc6189bb..9e94273d63 100644 --- a/lib/iris/tests/unit/fileformats/pp_load_rules/test__reduced_points_and_bounds.py +++ b/lib/iris/tests/unit/fileformats/pp_load_rules/test__reduced_points_and_bounds.py @@ -6,65 +6,61 @@ :func:`iris.fileformats.pp_load_rules._reduce_points_and_bounds`. """ - -# 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 from iris.fileformats.pp_load_rules import _reduce_points_and_bounds +from iris.tests._shared_utils import assert_array_equal -class Test(tests.IrisTest): +class Test: def test_scalar(self): array = np.array(1) dims, result, bounds = _reduce_points_and_bounds(array) - self.assertArrayEqual(result, array) - self.assertEqual(dims, None) - self.assertIsNone(bounds) + assert_array_equal(result, array) + assert dims is None + assert bounds is None def test_1d_nochange(self): array = np.array([1, 2, 3]) dims, result, _ = _reduce_points_and_bounds(array) - self.assertArrayEqual(result, array) - self.assertEqual(dims, (0,)) + assert_array_equal(result, array) + assert dims == (0,) def test_1d_collapse(self): array = np.array([1, 1, 1]) dims, result, _ = _reduce_points_and_bounds(array) - self.assertArrayEqual(result, np.array(1)) - self.assertEqual(dims, None) + assert_array_equal(result, np.array(1)) + assert dims is None def test_2d_nochange(self): array = np.array([[1, 2, 3], [4, 5, 6]]) dims, result, _ = _reduce_points_and_bounds(array) - self.assertArrayEqual(result, array) - self.assertEqual(dims, (0, 1)) + assert_array_equal(result, array) + assert dims == (0, 1) def test_2d_collapse_dim0(self): array = np.array([[1, 2, 3], [1, 2, 3]]) dims, result, _ = _reduce_points_and_bounds(array) - self.assertArrayEqual(result, np.array([1, 2, 3])) - self.assertEqual(dims, (1,)) + assert_array_equal(result, np.array([1, 2, 3])) + assert dims == (1,) def test_2d_collapse_dim1(self): array = np.array([[1, 1, 1], [2, 2, 2]]) dims, result, _ = _reduce_points_and_bounds(array) - self.assertArrayEqual(result, np.array([1, 2])) - self.assertEqual(dims, (0,)) + assert_array_equal(result, np.array([1, 2])) + assert dims == (0,) def test_2d_collapse_both(self): array = np.array([[3, 3, 3], [3, 3, 3]]) dims, result, _ = _reduce_points_and_bounds(array) - self.assertArrayEqual(result, np.array(3)) - self.assertEqual(dims, None) + assert_array_equal(result, np.array(3)) + assert dims is None def test_3d(self): array = np.array([[[3, 3, 3], [4, 4, 4]], [[3, 3, 3], [4, 4, 4]]]) dims, result, _ = _reduce_points_and_bounds(array) - self.assertArrayEqual(result, np.array([3, 4])) - self.assertEqual(dims, (1,)) + assert_array_equal(result, np.array([3, 4])) + assert dims == (1,) def test_bounds_collapse(self): points = np.array([1, 1, 1]) @@ -72,9 +68,9 @@ def test_bounds_collapse(self): result_dims, result_pts, result_bds = _reduce_points_and_bounds( points, (bounds[..., 0], bounds[..., 1]) ) - self.assertArrayEqual(result_pts, np.array(1)) - self.assertArrayEqual(result_bds, np.array([0, 2])) - self.assertEqual(result_dims, None) + assert_array_equal(result_pts, np.array(1)) + assert_array_equal(result_bds, np.array([0, 2])) + assert result_dims is None def test_bounds_no_collapse(self): points = np.array([1, 2, 3]) @@ -82,10 +78,6 @@ def test_bounds_no_collapse(self): result_dims, result_pts, result_bds = _reduce_points_and_bounds( points, (bounds[..., 0], bounds[..., 1]) ) - self.assertArrayEqual(result_pts, points) - self.assertArrayEqual(result_bds, bounds) - self.assertEqual(result_dims, (0,)) - - -if __name__ == "__main__": - tests.main() + assert_array_equal(result_pts, points) + assert_array_equal(result_bds, bounds) + assert result_dims == (0,) diff --git a/lib/iris/tests/unit/fileformats/pp_load_rules/test__reshape_vector_args.py b/lib/iris/tests/unit/fileformats/pp_load_rules/test__reshape_vector_args.py index 69ff56391e..38cf0b9cb9 100644 --- a/lib/iris/tests/unit/fileformats/pp_load_rules/test__reshape_vector_args.py +++ b/lib/iris/tests/unit/fileformats/pp_load_rules/test__reshape_vector_args.py @@ -6,27 +6,24 @@ :func:`iris.fileformats.pp_load_rules._reshape_vector_args`. """ - -# 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 pytest from iris.fileformats.pp_load_rules import _reshape_vector_args +from iris.tests._shared_utils import assert_array_equal -class TestEmpty(tests.IrisTest): +class TestEmpty: def test(self): result = _reshape_vector_args([]) - self.assertEqual(result, []) + assert result == [] -class TestSingleArg(tests.IrisTest): +class TestSingleArg: def _check(self, result, expected): - self.assertEqual(len(result), len(expected)) + assert len(result) == len(expected) for result_arr, expected_arr in zip(result, expected): - self.assertArrayEqual(result_arr, expected_arr) + assert_array_equal(result_arr, expected_arr) def test_nochange(self): points = np.array([[1, 2, 3], [4, 5, 6]]) @@ -36,7 +33,7 @@ def test_nochange(self): def test_bad_dimensions(self): points = np.array([[1, 2, 3], [4, 5, 6]]) - with self.assertRaisesRegex(ValueError, "Length"): + with pytest.raises(ValueError, match="Length"): _reshape_vector_args([(points, (0, 1, 2))]) def test_scalar(self): @@ -64,11 +61,11 @@ def test_extend(self): self._check(result, expected) -class TestMultipleArgs(tests.IrisTest): +class TestMultipleArgs: def _check(self, result, expected): - self.assertEqual(len(result), len(expected)) + assert len(result) == len(expected) for result_arr, expected_arr in zip(result, expected): - self.assertArrayEqual(result_arr, expected_arr) + assert_array_equal(result_arr, expected_arr) def test_nochange(self): a1 = np.array([[1, 2, 3], [4, 5, 6]]) @@ -131,7 +128,3 @@ def test_triple(self): a3.reshape(1, 1, 1), ] self._check(result, expected) - - -if __name__ == "__main__": - tests.main() diff --git a/lib/iris/tests/unit/fileformats/pp_load_rules/test_convert.py b/lib/iris/tests/unit/fileformats/pp_load_rules/test_convert.py index 476ecbc8ae..08a6398f2d 100644 --- a/lib/iris/tests/unit/fileformats/pp_load_rules/test_convert.py +++ b/lib/iris/tests/unit/fileformats/pp_load_rules/test_convert.py @@ -3,11 +3,6 @@ # This file is part of Iris and is released under the BSD license. # See LICENSE in the root of the repository for full licensing details. """Unit tests for :func:`iris.fileformats.pp_load_rules.convert`.""" - -# Import iris.tests first so that some things can be initialised before -# importing anything else. -import iris.tests as tests # isort:skip - from types import MethodType from unittest import mock @@ -17,10 +12,41 @@ from iris.fileformats.pp import STASH, PPField3, SplittableInt from iris.fileformats.pp_load_rules import convert -import iris.tests.unit.fileformats +from iris.tests._shared_utils import assert_array_equal from iris.util import guess_coord_axis +def assert_test_for_coord( + field, convert, coord_predicate, expected_points, expected_bounds +): + ( + factories, + references, + standard_name, + long_name, + units, + attributes, + cell_methods, + dim_coords_and_dims, + aux_coords_and_dims, + ) = convert(field) + + # Check for one and only one matching coordinate. + coords_and_dims = dim_coords_and_dims + aux_coords_and_dims + matching_coords = [coord for coord, _ in coords_and_dims if coord_predicate(coord)] + assert len(matching_coords) == 1, str(matching_coords) + coord = matching_coords[0] + + # Check points and bounds. + if expected_points is not None: + assert_array_equal(coord.points, expected_points) + + if expected_bounds is None: + assert coord.bounds is None + else: + assert_array_equal(coord.bounds, expected_bounds) + + def _mock_field(**kwargs): # Generate a mock field, but ensure T1 and T2 viable for rules. field = mock.MagicMock( @@ -31,7 +57,7 @@ def _mock_field(**kwargs): return field -class TestLBCODE(iris.tests.unit.fileformats.TestField): +class TestLBCODE: @staticmethod def _is_cross_section_height_coord(coord): return ( @@ -45,7 +71,7 @@ def test_cross_section_height_bdy_zero(self): points = np.array([10, 20, 30, 40]) bounds = np.array([[0, 15], [15, 25], [25, 35], [35, 45]]) field = _mock_field(lbcode=lbcode, bdy=0, y=points, y_bounds=bounds) - self._test_for_coord( + assert_test_for_coord( field, convert, TestLBCODE._is_cross_section_height_coord, @@ -61,7 +87,7 @@ def test_cross_section_height_bdy_bmdi(self): field = _mock_field( lbcode=lbcode, bdy=bmdi, bmdi=bmdi, y=points, y_bounds=bounds ) - self._test_for_coord( + assert_test_for_coord( field, convert, TestLBCODE._is_cross_section_height_coord, @@ -70,7 +96,7 @@ def test_cross_section_height_bdy_bmdi(self): ) -class TestLBVC(iris.tests.unit.fileformats.TestField): +class TestLBVC: @staticmethod def _is_potm_level_coord(coord): return ( @@ -113,7 +139,7 @@ def _is_soil_depth_coord(coord): def test_soil_levels(self): level = 1234 field = _mock_field(lbvc=6, lblev=level, brsvd=[0, 0], brlev=0) - self._test_for_coord( + assert_test_for_coord( field, convert, self._is_soil_model_level_number_coord, @@ -124,7 +150,7 @@ def test_soil_levels(self): def test_soil_depth(self): lower, point, upper = 1.2, 3.4, 5.6 field = _mock_field(lbvc=6, blev=point, brsvd=[lower, 0], brlev=upper) - self._test_for_coord( + assert_test_for_coord( field, convert, self._is_soil_depth_coord, @@ -143,7 +169,7 @@ def test_hybrid_pressure_model_level_number(self): bhrlev=45, brsvd=[17, 40], ) - self._test_for_coord( + assert_test_for_coord( field, convert, TestLBVC._is_model_level_number_coord, @@ -164,7 +190,7 @@ def test_hybrid_pressure_delta(self): bhrlev=delta_lower_bound, brsvd=[17, delta_upper_bound], ) - self._test_for_coord( + assert_test_for_coord( field, convert, TestLBVC._is_level_pressure_coord, @@ -185,7 +211,7 @@ def test_hybrid_pressure_sigma(self): bhrlev=11, brsvd=[sigma_upper_bound, 13], ) - self._test_for_coord( + assert_test_for_coord( field, convert, TestLBVC._is_sigma_coord, @@ -196,7 +222,7 @@ def test_hybrid_pressure_sigma(self): def test_potential_temperature_levels(self): potm_value = 27.32 field = _mock_field(lbvc=19, blev=potm_value) - self._test_for_coord( + assert_test_for_coord( field, convert, TestLBVC._is_potm_level_coord, @@ -205,7 +231,7 @@ def test_potential_temperature_levels(self): ) -class TestLBTIM(iris.tests.unit.fileformats.TestField): +class TestLBTIM: def test_365_calendar(self): f = mock.MagicMock( lbtim=SplittableInt(4, {"ia": 2, "ib": 1, "ic": 0}), @@ -238,10 +264,10 @@ def is_t_coord(coord_and_dims): return coord.standard_name == "time" coords_and_dims = list(filter(is_t_coord, aux_coords_and_dims)) - self.assertEqual(len(coords_and_dims), 1) + assert len(coords_and_dims) == 1 coord, dims = coords_and_dims[0] - self.assertEqual(guess_coord_axis(coord), "T") - self.assertEqual(coord.units.calendar, "365_day") + assert guess_coord_axis(coord) == "T" + assert coord.units.calendar == "365_day" def base_field(self): field = PPField3(header=mock.MagicMock()) @@ -278,7 +304,7 @@ def test_time_mean_ib2(self): field.lbyrd, field.lbmond, field.lbdatd = 1970, 1, 2 field.lbhrd, field.lbmind, field.lbsecd = 15, 0, 0 - self._test_for_coord( + assert_test_for_coord( field, convert, self.is_forecast_period, @@ -286,7 +312,7 @@ def test_time_mean_ib2(self): expected_bounds=[[6, 9]], ) - self._test_for_coord( + assert_test_for_coord( field, convert, self.is_time, @@ -306,7 +332,7 @@ def test_time_mean_ib3(self): field.lbyrd, field.lbmond, field.lbdatd = 1971, 1, 2 field.lbhrd, field.lbmind, field.lbsecd = 15, 0, 0 - self._test_for_coord( + assert_test_for_coord( field, convert, self.is_forecast_period, @@ -314,7 +340,7 @@ def test_time_mean_ib3(self): expected_bounds=[[36 - 30, lbft]], ) - self._test_for_coord( + assert_test_for_coord( field, convert, self.is_time, @@ -323,7 +349,7 @@ def test_time_mean_ib3(self): ) -class TestLBRSVD(iris.tests.unit.fileformats.TestField): +class TestLBRSVD: @staticmethod def _is_realization(coord): return coord.standard_name == "realization" and coord.units == "1" @@ -334,7 +360,7 @@ def test_realization(self): points = np.array([71]) bounds = None field = _mock_field(lbrsvd=lbrsvd) - self._test_for_coord( + assert_test_for_coord( field, convert, TestLBRSVD._is_realization, @@ -343,7 +369,7 @@ def test_realization(self): ) -class TestLBSRCE(iris.tests.IrisTest): +class TestLBSRCE: def check_um_source_attrs(self, lbsrce, source_str=None, um_version_str=None): field = _mock_field(lbsrce=lbsrce) ( @@ -358,13 +384,13 @@ def check_um_source_attrs(self, lbsrce, source_str=None, um_version_str=None): aux_coords_and_dims, ) = convert(field) if source_str is not None: - self.assertEqual(attributes["source"], source_str) + assert attributes["source"] == source_str else: - self.assertNotIn("source", attributes) + assert "source" not in attributes if um_version_str is not None: - self.assertEqual(attributes["um_version"], um_version_str) + assert attributes["um_version"] == um_version_str else: - self.assertNotIn("um_version", attributes) + assert "um_version" not in attributes def test_none(self): self.check_um_source_attrs(lbsrce=8123, source_str=None, um_version_str=None) @@ -384,7 +410,7 @@ def test_um_version(self): ) -class Test_STASH_CF(iris.tests.unit.fileformats.TestField): +class Test_STASH_CF: def test_stash_cf_air_temp(self): lbuser = [1, 0, 0, 16203, 0, 0, 1] lbfc = 16 @@ -401,8 +427,8 @@ def test_stash_cf_air_temp(self): dim_coords_and_dims, aux_coords_and_dims, ) = convert(field) - self.assertEqual(standard_name, "air_temperature") - self.assertEqual(units, "K") + assert standard_name == "air_temperature" + assert units == "K" def test_no_std_name(self): lbuser = [1, 0, 0, 0, 0, 0, 0] @@ -420,11 +446,11 @@ def test_no_std_name(self): dim_coords_and_dims, aux_coords_and_dims, ) = convert(field) - self.assertIsNone(standard_name) - self.assertIsNone(units) + assert standard_name is None + assert units is None -class Test_LBFC_CF(iris.tests.unit.fileformats.TestField): +class Test_LBFC_CF: def test_fc_cf_air_temp(self): lbuser = [1, 0, 0, 0, 0, 0, 0] lbfc = 16 @@ -441,9 +467,5 @@ def test_fc_cf_air_temp(self): dim_coords_and_dims, aux_coords_and_dims, ) = convert(field) - self.assertEqual(standard_name, "air_temperature") - self.assertEqual(units, "K") - - -if __name__ == "__main__": - tests.main() + assert standard_name == "air_temperature" + assert units == "K"