|
42 | 42 |
|
43 | 43 | import iris.config
|
44 | 44 | import iris.cube
|
| 45 | +import iris.fileformats |
45 | 46 | import iris.tests.graphics as graphics
|
46 | 47 | import iris.util
|
47 | 48 |
|
@@ -883,6 +884,93 @@ class GraphicsTest(graphics.GraphicsTestMixin, IrisTest):
|
883 | 884 | pass
|
884 | 885 |
|
885 | 886 |
|
| 887 | +class PPTest: |
| 888 | + """A mixin class to provide PP-specific utilities to subclasses of tests.IrisTest.""" |
| 889 | + |
| 890 | + @contextlib.contextmanager |
| 891 | + def cube_save_test( |
| 892 | + self, |
| 893 | + reference_txt_path, |
| 894 | + reference_cubes=None, |
| 895 | + reference_pp_path=None, |
| 896 | + **kwargs, |
| 897 | + ): |
| 898 | + """A context manager for testing the saving of Cubes to PP files. |
| 899 | +
|
| 900 | + Args: |
| 901 | +
|
| 902 | + * reference_txt_path: |
| 903 | + The path of the file containing the textual PP reference data. |
| 904 | +
|
| 905 | + Kwargs: |
| 906 | +
|
| 907 | + * reference_cubes: |
| 908 | + The cube(s) from which the textual PP reference can be re-built if necessary. |
| 909 | + * reference_pp_path: |
| 910 | + The location of a PP file from which the textual PP reference can be re-built if necessary. |
| 911 | + NB. The "reference_cubes" argument takes precedence over this argument. |
| 912 | +
|
| 913 | + The return value from the context manager is the name of a temporary file |
| 914 | + into which the PP data to be tested should be saved. |
| 915 | +
|
| 916 | + Example:: |
| 917 | + with self.cube_save_test(reference_txt_path, reference_cubes=cubes) as temp_pp_path: |
| 918 | + iris.save(cubes, temp_pp_path) |
| 919 | +
|
| 920 | + """ |
| 921 | + # Watch out for a missing reference text file |
| 922 | + if not os.path.isfile(reference_txt_path): |
| 923 | + if reference_cubes: |
| 924 | + temp_pp_path = iris.util.create_temp_filename(".pp") |
| 925 | + try: |
| 926 | + iris.save(reference_cubes, temp_pp_path, **kwargs) |
| 927 | + self._create_reference_txt(reference_txt_path, temp_pp_path) |
| 928 | + finally: |
| 929 | + os.remove(temp_pp_path) |
| 930 | + elif reference_pp_path: |
| 931 | + self._create_reference_txt(reference_txt_path, reference_pp_path) |
| 932 | + else: |
| 933 | + raise ValueError( |
| 934 | + "Missing all of reference txt file, cubes, and PP path." |
| 935 | + ) |
| 936 | + |
| 937 | + temp_pp_path = iris.util.create_temp_filename(".pp") |
| 938 | + try: |
| 939 | + # This value is returned to the target of the "with" statement's "as" clause. |
| 940 | + yield temp_pp_path |
| 941 | + |
| 942 | + # Load deferred data for all of the fields (but don't do anything with it) |
| 943 | + pp_fields = list(iris.fileformats.pp.load(temp_pp_path)) |
| 944 | + for pp_field in pp_fields: |
| 945 | + pp_field.data |
| 946 | + with open(reference_txt_path, "r") as reference_fh: |
| 947 | + reference = "".join(reference_fh) |
| 948 | + self._assert_str_same( |
| 949 | + reference + "\n", |
| 950 | + str(pp_fields) + "\n", |
| 951 | + reference_txt_path, |
| 952 | + type_comparison_name="PP files", |
| 953 | + ) |
| 954 | + finally: |
| 955 | + os.remove(temp_pp_path) |
| 956 | + |
| 957 | + def _create_reference_txt(self, txt_path, pp_path): |
| 958 | + # Load the reference data |
| 959 | + pp_fields = list(iris.fileformats.pp.load(pp_path)) |
| 960 | + for pp_field in pp_fields: |
| 961 | + pp_field.data |
| 962 | + |
| 963 | + # Clear any header words we don't use |
| 964 | + unused = ("lbexp", "lbegin", "lbnrec", "lbproj", "lbtyp") |
| 965 | + for pp_field in pp_fields: |
| 966 | + for word_name in unused: |
| 967 | + setattr(pp_field, word_name, 0) |
| 968 | + |
| 969 | + # Save the textual representation of the PP fields |
| 970 | + with open(txt_path, "w") as txt_file: |
| 971 | + txt_file.writelines(str(pp_fields)) |
| 972 | + |
| 973 | + |
886 | 974 | def skip_data(fn):
|
887 | 975 | """Decorator to choose whether to run tests, based on the availability of
|
888 | 976 | external data.
|
|
0 commit comments