From 61db6b9d6bdaabf4cce6ed1b27d9d273f93f77e5 Mon Sep 17 00:00:00 2001 From: Bill Little Date: Fri, 5 Jan 2024 13:36:11 +0000 Subject: [PATCH] move tests.pp to tests.__init__ --- lib/iris/tests/__init__.py | 88 ++++++++++++++++++++++++++++ lib/iris/tests/pp.py | 96 ------------------------------- lib/iris/tests/test_cdm.py | 3 +- lib/iris/tests/test_cube_to_pp.py | 5 +- lib/iris/tests/test_pp_cf.py | 3 +- 5 files changed, 92 insertions(+), 103 deletions(-) delete mode 100644 lib/iris/tests/pp.py diff --git a/lib/iris/tests/__init__.py b/lib/iris/tests/__init__.py index a1efe9d606..77a9fcdd67 100644 --- a/lib/iris/tests/__init__.py +++ b/lib/iris/tests/__init__.py @@ -42,6 +42,7 @@ import iris.config import iris.cube +import iris.fileformats import iris.tests.graphics as graphics import iris.util @@ -883,6 +884,93 @@ class GraphicsTest(graphics.GraphicsTestMixin, IrisTest): pass +class PPTest: + """A mixin class to provide PP-specific utilities to subclasses of tests.IrisTest.""" + + @contextlib.contextmanager + def cube_save_test( + self, + reference_txt_path, + reference_cubes=None, + reference_pp_path=None, + **kwargs, + ): + """A context manager for testing the saving of Cubes to PP files. + + Args: + + * reference_txt_path: + The path of the file containing the textual PP reference data. + + Kwargs: + + * reference_cubes: + The cube(s) from which the textual PP reference can be re-built if necessary. + * reference_pp_path: + The location of a PP file from which the textual PP reference can be re-built if necessary. + NB. The "reference_cubes" argument takes precedence over this argument. + + The return value from the context manager is the name of a temporary file + into which the PP data to be tested should be saved. + + Example:: + with self.cube_save_test(reference_txt_path, reference_cubes=cubes) as temp_pp_path: + iris.save(cubes, temp_pp_path) + + """ + # Watch out for a missing reference text file + if not os.path.isfile(reference_txt_path): + if reference_cubes: + temp_pp_path = iris.util.create_temp_filename(".pp") + try: + iris.save(reference_cubes, temp_pp_path, **kwargs) + self._create_reference_txt(reference_txt_path, temp_pp_path) + finally: + os.remove(temp_pp_path) + elif reference_pp_path: + self._create_reference_txt(reference_txt_path, reference_pp_path) + else: + raise ValueError( + "Missing all of reference txt file, cubes, and PP path." + ) + + temp_pp_path = iris.util.create_temp_filename(".pp") + try: + # This value is returned to the target of the "with" statement's "as" clause. + yield temp_pp_path + + # Load deferred data for all of the fields (but don't do anything with it) + pp_fields = list(iris.fileformats.pp.load(temp_pp_path)) + for pp_field in pp_fields: + pp_field.data + with open(reference_txt_path, "r") as reference_fh: + reference = "".join(reference_fh) + self._assert_str_same( + reference + "\n", + str(pp_fields) + "\n", + reference_txt_path, + type_comparison_name="PP files", + ) + finally: + os.remove(temp_pp_path) + + def _create_reference_txt(self, txt_path, pp_path): + # Load the reference data + pp_fields = list(iris.fileformats.pp.load(pp_path)) + for pp_field in pp_fields: + pp_field.data + + # Clear any header words we don't use + unused = ("lbexp", "lbegin", "lbnrec", "lbproj", "lbtyp") + for pp_field in pp_fields: + for word_name in unused: + setattr(pp_field, word_name, 0) + + # Save the textual representation of the PP fields + with open(txt_path, "w") as txt_file: + txt_file.writelines(str(pp_fields)) + + def skip_data(fn): """Decorator to choose whether to run tests, based on the availability of external data. diff --git a/lib/iris/tests/pp.py b/lib/iris/tests/pp.py deleted file mode 100644 index b0af72d5ee..0000000000 --- a/lib/iris/tests/pp.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright Iris contributors -# -# This file is part of Iris and is released under the BSD license. -# See LICENSE in the root of the repository for full licensing details. - -import contextlib -import os.path - -import iris - - -class PPTest: - """A mixin class to provide PP-specific utilities to subclasses of tests.IrisTest.""" - - @contextlib.contextmanager - def cube_save_test( - self, - reference_txt_path, - reference_cubes=None, - reference_pp_path=None, - **kwargs, - ): - """A context manager for testing the saving of Cubes to PP files. - - Args: - - * reference_txt_path: - The path of the file containing the textual PP reference data. - - Kwargs: - - * reference_cubes: - The cube(s) from which the textual PP reference can be re-built if necessary. - * reference_pp_path: - The location of a PP file from which the textual PP reference can be re-built if necessary. - NB. The "reference_cubes" argument takes precedence over this argument. - - The return value from the context manager is the name of a temporary file - into which the PP data to be tested should be saved. - - Example:: - with self.cube_save_test(reference_txt_path, reference_cubes=cubes) as temp_pp_path: - iris.save(cubes, temp_pp_path) - - """ - # Watch out for a missing reference text file - if not os.path.isfile(reference_txt_path): - if reference_cubes: - temp_pp_path = iris.util.create_temp_filename(".pp") - try: - iris.save(reference_cubes, temp_pp_path, **kwargs) - self._create_reference_txt(reference_txt_path, temp_pp_path) - finally: - os.remove(temp_pp_path) - elif reference_pp_path: - self._create_reference_txt(reference_txt_path, reference_pp_path) - else: - raise ValueError( - "Missing all of reference txt file, cubes, and PP path." - ) - - temp_pp_path = iris.util.create_temp_filename(".pp") - try: - # This value is returned to the target of the "with" statement's "as" clause. - yield temp_pp_path - - # Load deferred data for all of the fields (but don't do anything with it) - pp_fields = list(iris.fileformats.pp.load(temp_pp_path)) - for pp_field in pp_fields: - pp_field.data - with open(reference_txt_path, "r") as reference_fh: - reference = "".join(reference_fh) - self._assert_str_same( - reference + "\n", - str(pp_fields) + "\n", - reference_txt_path, - type_comparison_name="PP files", - ) - finally: - os.remove(temp_pp_path) - - def _create_reference_txt(self, txt_path, pp_path): - # Load the reference data - pp_fields = list(iris.fileformats.pp.load(pp_path)) - for pp_field in pp_fields: - pp_field.data - - # Clear any header words we don't use - unused = ("lbexp", "lbegin", "lbnrec", "lbproj", "lbtyp") - for pp_field in pp_fields: - for word_name in unused: - setattr(pp_field, word_name, 0) - - # Save the textual representation of the PP fields - with open(txt_path, "w") as txt_file: - txt_file.writelines(str(pp_fields)) diff --git a/lib/iris/tests/test_cdm.py b/lib/iris/tests/test_cdm.py index 5f8b247b79..f27dae2314 100644 --- a/lib/iris/tests/test_cdm.py +++ b/lib/iris/tests/test_cdm.py @@ -23,7 +23,6 @@ import iris.cube import iris.fileformats import iris.fileformats.dot -import iris.tests.pp as pp import iris.tests.stock @@ -1287,7 +1286,7 @@ def test_non_string_attributes(self): @tests.skip_data -class TestMaskedData(tests.IrisTest, pp.PPTest): +class TestMaskedData(tests.IrisTest, tests.PPTest): def _load_3d_cube(self): # This 3D data set has a missing a slice with SOME missing values. # The missing data is in the pressure = 1000 hPa, forcast_period = 0, diff --git a/lib/iris/tests/test_cube_to_pp.py b/lib/iris/tests/test_cube_to_pp.py index e75edee9cd..6ae4567f49 100644 --- a/lib/iris/tests/test_cube_to_pp.py +++ b/lib/iris/tests/test_cube_to_pp.py @@ -17,7 +17,6 @@ import iris.coords import iris.fileformats.pp from iris.fileformats.pp import PPField3 -import iris.tests.pp as pp import iris.tests.stock as stock import iris.util @@ -36,7 +35,7 @@ def itab_callback(cube, field, filename): @tests.skip_data -class TestPPSave(tests.IrisTest, pp.PPTest): +class TestPPSave(tests.IrisTest, tests.PPTest): def test_no_forecast_time(self): cube = stock.lat_lon_cube() coord = iris.coords.DimCoord( @@ -276,7 +275,7 @@ def geog_cs(self): return iris.coord_systems.GeogCS(6371229.0) -class TestPPSaveRules(tests.IrisTest, pp.PPTest): +class TestPPSaveRules(tests.IrisTest, tests.PPTest): def test_default_coord_system(self): GeogCS = iris.coord_systems.GeogCS cube = iris.tests.stock.lat_lon_cube() diff --git a/lib/iris/tests/test_pp_cf.py b/lib/iris/tests/test_pp_cf.py index 1495fd65d1..8b0af5a5c3 100644 --- a/lib/iris/tests/test_pp_cf.py +++ b/lib/iris/tests/test_pp_cf.py @@ -13,7 +13,6 @@ import iris.coords from iris.fileformats.netcdf import _thread_safe_nc from iris.fileformats.pp import STASH -import iris.tests.pp as pp import iris.util @@ -64,7 +63,7 @@ def callback_aaxzc_n10r13xy_b_pp(cube, field, filename): @tests.skip_data -class TestAll(tests.IrisTest, pp.PPTest): +class TestAll(tests.IrisTest, tests.PPTest): _ref_dir = ("usecases", "pp_to_cf_conversion") def _test_file(self, name):