def test_masked_data__insitu(self): # Test that the error is raised in the right place. with self.temp_filename('.nc') as nc_path: saver = Saver(nc_path, 'NETCDF4') with self.assertRaisesRegexp(ValueError, self.exp_emsg): saver._create_cf_cell_measure_variable(self.cube, self.names_map, self.cm)
def test_masked_data__insitu(self): # Test that the error is raised in the right place. with self.temp_filename(".nc") as nc_path: saver = Saver(nc_path, "NETCDF4") with self.assertRaisesRegex(ValueError, self.exp_emsg): saver._create_generic_cf_array_var(self.cube, self.names_map, self.cm)
def _grid_mapping_variable(self, coord_system): """ Return a mock netCDF variable that represents the conversion of the given coordinate system. """ cube = self._cube_with_cs(coord_system) class NCMock(mock.Mock): def setncattr(self, name, attr): setattr(self, name, attr) # Calls the actual NetCDF saver with appropriate mocking, returning # the grid variable that gets created. grid_variable = NCMock(name='NetCDFVariable') create_var_fn = mock.Mock(side_effect=[grid_variable]) dataset = mock.Mock(variables=[], createVariable=create_var_fn) saver = mock.Mock(spec=Saver, _coord_systems=[], _dataset=dataset) variable = NCMock() # This is the method we're actually testing! Saver._create_cf_grid_mapping(saver, cube, variable) self.assertEqual(create_var_fn.call_count, 1) self.assertEqual(variable.grid_mapping, grid_variable.grid_mapping_name) return grid_variable
def construct_cf_grid_mapping_variable(self, cube): # Calls the actual NetCDF saver with appropriate mocking, returning # the grid variable that gets created. grid_variable = mock.Mock(name='NetCDFVariable') create_var_fn = mock.Mock(side_effect=[grid_variable]) dataset = mock.Mock(variables=[], createVariable=create_var_fn) saver = mock.Mock(spec=Saver, _coord_systems=[], _dataset=dataset) variable = mock.Mock() Saver._create_cf_grid_mapping(saver, cube, variable) self.assertEqual(create_var_fn.call_count, 1) self.assertEqual(variable.grid_mapping, grid_variable.grid_mapping_name) return grid_variable
def check_call(self, coord_name, coord_system, units, expected_units): coord = iris.coords.DimCoord([30, 45], coord_name, units=units, coord_system=coord_system) result = Saver._cf_coord_standardised_units(coord) self.assertEqual(result, expected_units)
def test_mercator_no_ellipsoid(self): # Create a Cube with a Mercator coordinate system. cube = self._mercator_cube() with self.temp_filename('.nc') as nc_path: with Saver(nc_path, 'NETCDF4') as saver: saver.write(cube) self.assertCDL(nc_path)
def test_transverse_mercator_no_ellipsoid(self): # Create a Cube with a transverse Mercator coordinate system. cube = self._transverse_mercator_cube() with self.temp_filename(".nc") as nc_path: with Saver(nc_path, "NETCDF4") as saver: saver.write(cube) self.assertCDL(nc_path)
def test_big_endian(self): # Create a Cube with big-endian data. cube = self._simple_cube('>f4') with self.temp_filename('.nc') as nc_path: with Saver(nc_path, 'NETCDF4') as saver: saver.write(cube) self.assertCDL(nc_path, basename='endian', flags='')
def test_stereographic_no_ellipsoid(self): # Create a Cube with a stereographic coordinate system. cube = self._stereo_cube() with self.temp_filename('.nc') as nc_path: with Saver(nc_path, 'NETCDF4') as saver: saver.write(cube) self.assertCDL(nc_path)
def test_stereographic(self): # Create a Cube with a stereographic coordinate system. ellipsoid = GeogCS(6377563.396, 6356256.909) cube = self._stereo_cube(ellipsoid) with self.temp_filename('.nc') as nc_path: with Saver(nc_path, 'NETCDF4') as saver: saver.write(cube) self.assertCDL(nc_path)
def test_big_endian(self): # Create a Cube with big-endian data. cube = self._simple_cube(">f4") with self.temp_filename(".nc") as nc_path: with Saver(nc_path, "NETCDF4") as saver: saver.write(cube) result_path = self.result_path("endian", "cdl") self.assertCDL(nc_path, result_path, flags="")
def test_big_endian(self): # Create a Cube with big-endian data. cube = self._simple_cube('>f4') with self.temp_filename('nc') as nc_path: with Saver(nc_path, 'NETCDF4') as saver: saver.write(cube) self.assertCDL(nc_path, ('unit', 'fileformats', 'netcdf', 'Saver', 'write', 'endian.cdl'), flags='')
def test_transverse_mercator(self): # Create a Cube with a transverse Mercator coordinate system. ellipsoid = GeogCS(6377563.396, 6356256.909) cube = self._transverse_mercator_cube(ellipsoid) with self.temp_filename('.nc') as nc_path: with Saver(nc_path, 'NETCDF4') as saver: saver.write(cube) self.assertCDL(nc_path)
def test_little_endian(self): # Create a Cube with little-endian data. cube = self._simple_cube('<f4') with self.temp_filename('.nc') as nc_path: with Saver(nc_path, 'NETCDF4') as saver: saver.write(cube) result_path = self.result_path('endian', 'cdl') self.assertCDL(nc_path, result_path, flags='')
def _check_bounds_setting(self, climatological=False): # Generic test that can run with or without a climatological coord. cube = stock.climatology_3d() coord = cube.coord("time").copy() # Over-write original value from stock.climatology_3d with test value. coord.climatological = climatological # Set up expected strings. if climatological: property_name = "climatology" varname_extra = "climatology" else: property_name = "bounds" varname_extra = "bnds" boundsvar_name = "time_" + varname_extra # Set up arguments for testing _create_cf_bounds. saver = mock.MagicMock(spec=Saver) # NOTE: 'saver' must have spec=Saver to fake isinstance(save, Saver), # so it can pass as 'self' in the call to _create_cf_cbounds. # Mock a '_dataset' property; not automatic because 'spec=Saver'. saver._dataset = mock.MagicMock() # Mock the '_ensure_valid_dtype' method to return an object with a # suitable 'shape' and 'dtype'. saver._ensure_valid_dtype.return_value = mock.Mock( shape=coord.bounds.shape, dtype=coord.bounds.dtype ) var = mock.MagicMock(spec=nc.Variable) # Make the main call. Saver._create_cf_bounds(saver, coord, var, "time") # Test the call of _setncattr in _create_cf_bounds. setncattr_call = mock.call( property_name, boundsvar_name.encode(encoding="ascii") ) self.assertEqual(setncattr_call, var.setncattr.call_args) # Test the call of createVariable in _create_cf_bounds. dataset = saver._dataset expected_dimensions = var.dimensions + ("bnds",) create_var_call = mock.call( boundsvar_name, coord.bounds.dtype, expected_dimensions ) self.assertEqual(create_var_call, dataset.createVariable.call_args)
def test_no_unlimited_dimensions(self): cube = self._simple_cube(">f4") with self.temp_filename(".nc") as nc_path: with Saver(nc_path, "NETCDF4") as saver: saver.write(cube, unlimited_dimensions=None) ds = nc.Dataset(nc_path) for dim in ds.dimensions.values(): self.assertFalse(dim.isunlimited()) ds.close()
def test_lazy_preserved_save(self): fpath = tests.get_data_path( ('NetCDF', 'label_and_climate', 'small_FC_167_mon_19601101.nc')) acube = iris.load_cube(fpath) self.assertTrue(acube.has_lazy_data()) with self.temp_filename('.nc') as nc_path: with Saver(nc_path, 'NETCDF4') as saver: saver.write(acube) self.assertTrue(acube.has_lazy_data())
def test_no_unlimited_dimensions(self): cube = self._simple_cube('>f4') with self.temp_filename('.nc') as nc_path: with Saver(nc_path, 'NETCDF4') as saver: saver.write(cube, unlimited_dimensions=None) ds = nc.Dataset(nc_path) for dim in six.itervalues(ds.dimensions): self.assertFalse(dim.isunlimited()) ds.close()
def test_lazy_preserved_save(self): fpath = tests.get_data_path( ("NetCDF", "label_and_climate", "small_FC_167_mon_19601101.nc")) acube = iris.load_cube(fpath, "air_temperature") self.assertTrue(acube.has_lazy_data()) with self.temp_filename(".nc") as nc_path: with Saver(nc_path, "NETCDF4") as saver: saver.write(acube) self.assertTrue(acube.has_lazy_data())
def test_transverse_mercator_no_ellipsoid(self): # Create a Cube with a transverse Mercator coordinate system. cube = self._transverse_mercator_cube() with self.temp_filename('nc') as nc_path: with Saver(nc_path, 'NETCDF4') as saver: saver.write(cube) self.assertCDL(nc_path, ('unit', 'fileformats', 'netcdf', 'Saver', 'write', 'transverse_mercator_no_ellipsoid.cdl'))
def test_default_unlimited_dimensions(self): cube = self._simple_cube('>f4') with self.temp_filename('.nc') as nc_path: with Saver(nc_path, 'NETCDF4') as saver: saver.write(cube) ds = nc.Dataset(nc_path) self.assertTrue(ds.dimensions['dim0'].isunlimited()) self.assertFalse(ds.dimensions['dim1'].isunlimited()) ds.close()
def test_valid_range_and_valid_min_valid_max_provided(self): # Conflicting attributes should raise a suitable exception. self.data = self.data.astype('int8') self.container.attributes['valid_range'] = [1, 2] self.container.attributes['valid_min'] = [1] msg = 'Both "valid_range" and "valid_min"' with Saver(mock.Mock(), 'NETCDF4') as saver: with self.assertRaisesRegexp(ValueError, msg): saver.check_attribute_compliance(self.container, self.data)
def test_reserved_attributes(self): cube = self._simple_cube('>f4') cube.attributes['dimensions'] = 'something something_else' with self.temp_filename('.nc') as nc_path: with Saver(nc_path, 'NETCDF4') as saver: saver.write(cube) ds = nc.Dataset(nc_path) res = ds.getncattr('dimensions') ds.close() self.assertEqual(res, 'something something_else')
def test_default_unlimited_dimensions(self): # Default is no unlimited dimensions. cube = self._simple_cube(">f4") with self.temp_filename(".nc") as nc_path: with Saver(nc_path, "NETCDF4") as saver: saver.write(cube) ds = nc.Dataset(nc_path) self.assertFalse(ds.dimensions["dim0"].isunlimited()) self.assertFalse(ds.dimensions["dim1"].isunlimited()) ds.close()
def test_reserved_attributes(self): cube = self._simple_cube(">f4") cube.attributes["dimensions"] = "something something_else" with self.temp_filename(".nc") as nc_path: with Saver(nc_path, "NETCDF4") as saver: saver.write(cube) ds = nc.Dataset(nc_path) res = ds.getncattr("dimensions") ds.close() self.assertEqual(res, "something something_else")
def test_valid_range_and_valid_min_valid_max_provided(self): # Conflicting attributes should raise a suitable exception. self.data_dtype = np.dtype("int8") self.container.attributes["valid_range"] = [1, 2] self.container.attributes["valid_min"] = [1] msg = 'Both "valid_range" and "valid_min"' with Saver(mock.Mock(), "NETCDF4") as saver: with self.assertRaisesRegex(ValueError, msg): saver.check_attribute_compliance(self.container, self.data_dtype)
def test_valid_max_saved(self): cube = tests.stock.lat_lon_cube() cube.data = cube.data.astype("int32") cube.coord(axis="x").attributes["valid_max"] = 2 with self.temp_filename(".nc") as nc_path: with Saver(nc_path, "NETCDF4") as saver: saver.write(cube, unlimited_dimensions=[]) ds = nc.Dataset(nc_path) self.assertArrayEqual(ds.variables["longitude"].valid_max, 2) ds.close()
def test_valid_min_saved(self): cube = tests.stock.lat_lon_cube() cube.data = cube.data.astype('int32') cube.attributes['valid_min'] = 1 with self.temp_filename('.nc') as nc_path: with Saver(nc_path, 'NETCDF4') as saver: saver.write(cube, unlimited_dimensions=[]) ds = nc.Dataset(nc_path) self.assertArrayEqual(ds.valid_min, 1) ds.close()
def test_valid_max_saved(self): cube = tests.stock.lat_lon_cube() cube.data = cube.data.astype('int32') cube.coord(axis='x').attributes['valid_max'] = 2 with self.temp_filename('.nc') as nc_path: with Saver(nc_path, 'NETCDF4') as saver: saver.write(cube, unlimited_dimensions=[]) ds = nc.Dataset(nc_path) self.assertArrayEqual(ds.variables['longitude'].valid_max, 2) ds.close()
def _netCDF_var(self, cube, **kwargs): # Get the netCDF4 Variable for a cube from a temp file standard_name = cube.standard_name with self.temp_filename('.nc') as nc_path: with Saver(nc_path, 'NETCDF4') as saver: saver.write(cube, **kwargs) ds = nc.Dataset(nc_path) var, = [ var for var in ds.variables.values() if var.standard_name == standard_name ] yield var
def check_call(self, coord_name, coord_system, units, expected_units): coord = iris.coords.DimCoord([30, 45], coord_name, units=units, coord_system=coord_system) result = Saver._cf_coord_identity(coord) self.assertEqual(result, (coord.standard_name, coord.long_name, expected_units))
def test_no_hyphen(self): # CF explicitly prohibits hyphen, even though it is fine in NetCDF. self.assertEqual(Saver.cf_valid_var_name('valid-netcdf'), 'valid_netcdf')
def test_no_replacement(self): self.assertEqual(Saver.cf_valid_var_name('valid_Nam3'), 'valid_Nam3')
def test_leading_invalid(self): self.assertEqual(Saver.cf_valid_var_name('?invalid'), 'var__invalid')
def test_special_chars(self): self.assertEqual(Saver.cf_valid_var_name('inv?alid'), 'inv_alid')
def test_leading_underscore(self): self.assertEqual(Saver.cf_valid_var_name('_invalid'), 'var__invalid')
def test_leading_number(self): self.assertEqual(Saver.cf_valid_var_name('2invalid'), 'var_2invalid')