diff --git a/Changelog.rst b/Changelog.rst index af6059b0c6..04608aac45 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -1,22 +1,3 @@ -version NEXTVERSION + 1 ------------------------ - -**2024-??-??** - -* Allow access to netCDF-4 files in S3 object stores - (https://github.com/NCAS-CMS/cf-python/issues/712) -* New class `cf.H5netcdfArray` -* New class `cf.NetCDF4Array` -* New class `cf.CFAH5netcdfArray` -* New class `cf.CFANetCDF4Array` -* New dependency: ``h5netcdf>=1.3.0`` -* New dependency: ``h5py>=3.10.0`` -* New dependency: ``s3fs>=2024.2.0`` -* Changed dependency: ``1.11.2.0<=cfdm<1.11.3.0`` -* Changed dependency: ``cfunits>=3.3.7`` - ----- - version NEXTVERSION ------------------- @@ -33,6 +14,12 @@ version NEXTVERSION * New keyword parameter to `cf.Field.derivative`: ``ignore_coordinate_units`` (https://github.com/NCAS-CMS/cf-python/issues/807) +* Allow access to netCDF-4 files in S3 object stores + (https://github.com/NCAS-CMS/cf-python/issues/712) +* New class `cf.H5netcdfArray` +* New class `cf.NetCDF4Array` +* New class `cf.CFAH5netcdfArray` +* New class `cf.CFANetCDF4Array` * Fix bug that sometimes puts an incorrect ``radian-1`` or ``radian-2`` in the returned units of the differential operator methods and functions @@ -46,9 +33,14 @@ version NEXTVERSION * Fix bug where `cf.normalize_slice` doesn't correctly handle certain cyclic slices (https://github.com/NCAS-CMS/cf-python/issues/774) -* Fix bug where `cf.Field.subspace` doesn't also correctly - handle some global cyclic subspaces +* Fix bug where `cf.Field.subspace` doesn't always correctly handle + global cyclic subspaces (https://github.com/NCAS-CMS/cf-python/issues/828) +* New dependency: ``h5netcdf>=1.3.0`` +* New dependency: ``h5py>=3.10.0`` +* New dependency: ``s3fs>=2024.2.0`` +* Changed dependency: ``1.11.2.0<=cfdm<1.11.3.0`` +* Changed dependency: ``cfunits>=3.3.7`` ---- diff --git a/cf/query.py b/cf/query.py index 87ff0c1c5b..268ca7b6d0 100644 --- a/cf/query.py +++ b/cf/query.py @@ -166,10 +166,11 @@ class Query: evaluated. ====================== ============================================== - In general, each method must have the query value as it's only - parameter. The only exception is for `__query_isclose__`, which + In general, each method must have the query value as its only + parameter. The only exceptions are for `__query_isclose__`, which also requires the absolute and relative numerical tolerances to be - provided. + provided, and for `__query_wi__`, which also requires upper and + lower interval openness Booleans to be provided. When the condition is on an attribute, or nested attributes, of the operand, the query interface method is looked for on the @@ -972,7 +973,7 @@ def _evaluate(self, x, parent_attr): if operator == "wi": _wi = getattr(x, "__query_wi__", None) if _wi is not None: - return _wi(value) + return _wi(value, self.open_lower, self.open_upper) if self.open_lower: lower_bound = x > value[0] diff --git a/cf/test/test_Data.py b/cf/test/test_Data.py index a62b49b76e..e29c192062 100644 --- a/cf/test/test_Data.py +++ b/cf/test/test_Data.py @@ -1479,7 +1479,6 @@ def test_Data__getitem__(self): f = cf.Data([-999, 35], mask=[True, False]).reshape(2, 1) self.assertTrue(e.equals(f)) - # REVIEW: getitem: `test_Data__getitem__`: Chained subspaces reading from disk # Chained subspaces reading from disk f = cf.read(self.filename)[0] d = f.data @@ -3290,7 +3289,6 @@ def test_Data_rechunk(self): self.assertEqual(e.chunks, ((4,), (5,))) self.assertTrue(e.equals(d)) - # REVIEW: getitem: `test_Data_rechunk`: rechunking after a __getitem__ # Test rechunking after a __getitem__ e = d[:2].rechunk((2, 5)) self.assertTrue(e.equals(d[:2])) @@ -4520,7 +4518,6 @@ def test_Data__str__(self): for element in elements0: self.assertNotIn(element, d._get_cached_elements()) - # REVIEW: getitem: `test_Data_cull_graph`: prevent new asanyarray layer def test_Data_cull_graph(self): """Test `Data.cull`""" # Note: The number of layers in the culled graphs include a @@ -4779,7 +4776,6 @@ def test_Data_pad_missing(self): with self.assertRaises(ValueError): d.pad_missing(99, to_size=99) - # REVIEW: getitem: `test_Data_is_masked`: test `Data.is_masked` def test_Data_is_masked(self): """Test Data.is_masked.""" d = cf.Data(np.arange(6).reshape(2, 3)) diff --git a/cf/test/test_FullArray.py b/cf/test/test_FullArray.py index 8b25642686..63dcb84f34 100644 --- a/cf/test/test_FullArray.py +++ b/cf/test/test_FullArray.py @@ -1,4 +1,3 @@ -# REVIEW: getitem: `test_FullArray`: new test module import datetime import faulthandler import unittest diff --git a/cf/test/test_NetCDF4Array.py b/cf/test/test_NetCDF4Array.py index 35d76581be..0d049ff497 100644 --- a/cf/test/test_NetCDF4Array.py +++ b/cf/test/test_NetCDF4Array.py @@ -12,7 +12,6 @@ import cf -# REVIEW: h5: `test_NetCDF4Array.py`: renamed 'NetCDFArray' to 'NetCDF4Array' n_tmpfiles = 1 tmpfiles = [ tempfile.mkstemp("_test_NetCDF4Array.nc", dir=os.getcwd())[1] @@ -41,7 +40,6 @@ class NetCDF4ArrayTest(unittest.TestCase): dtype=np.dtype(float), ) - # REVIEW: h5: `test_NetCDF4Array`: renamed 'NetCDFArray' to 'NetCDF4Array' def test_NetCDF4Array_del_file_location(self): a = cf.NetCDF4Array(("/data1/file1", "/data2/file2"), ("tas1", "tas2")) b = a.del_file_location("/data1") @@ -62,7 +60,6 @@ def test_NetCDF4Array_del_file_location(self): with self.assertRaises(ValueError): b.del_file_location("/data1/") - # REVIEW: h5: `test_NetCDF4Array`: renamed 'NetCDFArray' to 'NetCDF4Array' def test_NetCDF4Array_file_locations(self): a = cf.NetCDF4Array("/data1/file1") self.assertEqual(a.file_locations(), ("/data1",)) @@ -73,7 +70,6 @@ def test_NetCDF4Array_file_locations(self): a = cf.NetCDF4Array(("/data1/file1", "/data2/file2", "/data1/file2")) self.assertEqual(a.file_locations(), ("/data1", "/data2", "/data1")) - # REVIEW: h5: `test_NetCDF4Array`: renamed 'NetCDFArray' to 'NetCDF4Array' def test_NetCDF4Array_add_file_location(self): a = cf.NetCDF4Array("/data1/file1", "tas") b = a.add_file_location("/home/user") @@ -109,7 +105,6 @@ def test_NetCDF4Array_add_file_location(self): self.assertEqual(b.get_filenames(), a.get_filenames()) self.assertEqual(b.get_addresses(), a.get_addresses()) - # REVIEW: h5: `test_NetCDF4Array`: renamed 'NetCDFArray' to 'NetCDF4Array' def test_NetCDF4Array__dask_tokenize__(self): a = cf.NetCDF4Array("/data1/file1", "tas", shape=(12, 2), mask=False) self.assertEqual(tokenize(a), tokenize(a.copy())) @@ -117,7 +112,6 @@ def test_NetCDF4Array__dask_tokenize__(self): b = cf.NetCDF4Array("/home/file2", "tas", shape=(12, 2)) self.assertNotEqual(tokenize(a), tokenize(b)) - # REVIEW: h5: `test_NetCDF4Array`: renamed 'NetCDFArray' to 'NetCDF4Array' def test_NetCDF4Array_multiple_files(self): f = cf.example_field(0) cf.write(f, tmpfile1) @@ -135,7 +129,6 @@ def test_NetCDF4Array_multiple_files(self): self.assertEqual(len(n.get_filenames()), 2) self.assertTrue((n[...] == f.array).all()) - # REVIEW: getitem: `test_NetCDF4Array`: test `NetCDF4Array.shape` def test_NetCDF4Array_shape(self): shape = (12, 73, 96) a = cf.NetCDF4Array("/home/file2", "tas", shape=shape) @@ -145,7 +138,6 @@ def test_NetCDF4Array_shape(self): self.assertEqual(a.shape, (shape[0] // 2,) + shape[1:]) self.assertEqual(a.original_shape, shape) - # REVIEW: getitem: `test_NetCDF4Array`: test `NetCDF4Array.index` def test_NetCDF4Array_index(self): shape = (12, 73, 96) a = cf.NetCDF4Array("/home/file2", "tas", shape=shape) diff --git a/cf/test/test_active_storage.py b/cf/test/test_active_storage.py index 8c7af64bdc..f14e063849 100644 --- a/cf/test/test_active_storage.py +++ b/cf/test/test_active_storage.py @@ -1,4 +1,3 @@ -# REVIEW: h5: `test_active_storage.py`: new test module import atexit import datetime import faulthandler diff --git a/cf/test/test_functions.py b/cf/test/test_functions.py index 32bc3c4bd1..f6cce13ae0 100644 --- a/cf/test/test_functions.py +++ b/cf/test/test_functions.py @@ -47,7 +47,6 @@ def test_aliases(self): self.assertEqual(cf.tempdir(), cf.TEMPDIR()) self.assertEqual(cf.chunksize(), cf.CHUNKSIZE()) - # REVIEW: active: `test_configuration`: test `cf.active_storage`, cf.active_storage_url`, cf.active_storage_max_requests` def test_configuration(self): # This test assumes 'total_memory' remains constant throughout # the test run, which should be true generally in any diff --git a/cf/test/test_read_write.py b/cf/test/test_read_write.py index fb0b88055f..f0bf697fac 100644 --- a/cf/test/test_read_write.py +++ b/cf/test/test_read_write.py @@ -79,7 +79,6 @@ def test_write_filename(self): self.assertTrue((a == g[0].array).all()) - # REVIEW: h5: `test_read_mask`: rename numpy to np def test_read_mask(self): f = self.f0.copy() @@ -561,7 +560,6 @@ def test_read_write_netCDF4_compress_shuffle(self): f"Bad read/write with lossless compression: {fmt}", ) - # REVIEW: h5: `test_write_datatype`: rename numpy to np def test_write_datatype(self): f = cf.read(self.filename)[0] self.assertEqual(f.dtype, np.dtype(float))