From 57756ac31a787a1f2f5d07c46483cbcc8d224c8b Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 6 Sep 2019 11:17:08 +0200 Subject: [PATCH 1/9] Add hypothesis test for roundtrip to netCDF4 --- properties/test_netcdf_roundtrip.py | 47 +++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 properties/test_netcdf_roundtrip.py diff --git a/properties/test_netcdf_roundtrip.py b/properties/test_netcdf_roundtrip.py new file mode 100644 index 00000000000..1a54adf9202 --- /dev/null +++ b/properties/test_netcdf_roundtrip.py @@ -0,0 +1,47 @@ +""" +Property-based tests for round-tripping data to netCDF +""" +import hypothesis.extra.numpy as npst +import hypothesis.strategies as st +from hypothesis import given, settings + +import xarray as xr + +# Run for a while - arrays are a bigger search space than usual +settings.register_profile("ci", deadline=None) +settings.load_profile("ci") + + +an_array = npst.arrays( + dtype=st.one_of( + npst.unsigned_integer_dtypes(), npst.integer_dtypes(), + # NetCDF does not support float16 + # https://www.unidata.ucar.edu/software/netcdf/docs/data_type.html + npst.floating_dtypes(sizes=(32, 64)) + ), + shape=npst.array_shapes(max_side=3), # max_side specified for performance +) + +compatible_names = st.text( + alphabet=st.characters( + whitelist_categories=('Ll', 'Lu', 'Nd'), + # It looks like netCDF should allow unicode names, but removing + # this causes a failure with 'ά' + max_codepoint=255 + ), + min_size=1 +) + +@given(st.data(), an_array) +def test_netcdf_roundtrip(tmp_path, data, arr): + names = data.draw( + st.lists(compatible_names, min_size=arr.ndim, max_size=arr.ndim, unique=True).map( + tuple + ) + ) + var = xr.Variable(names, arr) + original = xr.Dataset({'data': var}) + original.to_netcdf(tmp_path / 'test.nc') + + roundtripped = xr.open_dataset(tmp_path / 'test.nc') + xr.testing.assert_identical(original, roundtripped) From 50d242e5a9f2e358c6a8690b96b032a2e867b24c Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 6 Sep 2019 11:18:19 +0200 Subject: [PATCH 2/9] Note how to run hypothesis tests --- properties/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/properties/README.md b/properties/README.md index 711062a2473..077be384a57 100644 --- a/properties/README.md +++ b/properties/README.md @@ -8,6 +8,8 @@ They are stored in a separate directory because they tend to run more examples and thus take longer, and so that local development can run a test suite without needing to `pip install hypothesis`. +To run these tests, run `pytest` in this directory. + ## Hang on, "property-based" tests? Instead of making assertions about operations on a particular piece of From 3230c2f4a522d2c6b19411398f4b3b70367c5d27 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 6 Sep 2019 11:40:16 +0200 Subject: [PATCH 3/9] Reformat code with black --- properties/test_netcdf_roundtrip.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/properties/test_netcdf_roundtrip.py b/properties/test_netcdf_roundtrip.py index 1a54adf9202..9f1813a52b4 100644 --- a/properties/test_netcdf_roundtrip.py +++ b/properties/test_netcdf_roundtrip.py @@ -14,34 +14,36 @@ an_array = npst.arrays( dtype=st.one_of( - npst.unsigned_integer_dtypes(), npst.integer_dtypes(), + npst.unsigned_integer_dtypes(), + npst.integer_dtypes(), # NetCDF does not support float16 # https://www.unidata.ucar.edu/software/netcdf/docs/data_type.html - npst.floating_dtypes(sizes=(32, 64)) + npst.floating_dtypes(sizes=(32, 64)), ), shape=npst.array_shapes(max_side=3), # max_side specified for performance ) compatible_names = st.text( alphabet=st.characters( - whitelist_categories=('Ll', 'Lu', 'Nd'), + whitelist_categories=("Ll", "Lu", "Nd"), # It looks like netCDF should allow unicode names, but removing # this causes a failure with 'ά' - max_codepoint=255 + max_codepoint=255, ), - min_size=1 + min_size=1, ) + @given(st.data(), an_array) def test_netcdf_roundtrip(tmp_path, data, arr): names = data.draw( - st.lists(compatible_names, min_size=arr.ndim, max_size=arr.ndim, unique=True).map( - tuple - ) + st.lists( + compatible_names, min_size=arr.ndim, max_size=arr.ndim, unique=True + ).map(tuple) ) var = xr.Variable(names, arr) - original = xr.Dataset({'data': var}) - original.to_netcdf(tmp_path / 'test.nc') + original = xr.Dataset({"data": var}) + original.to_netcdf(tmp_path / "test.nc") - roundtripped = xr.open_dataset(tmp_path / 'test.nc') + roundtripped = xr.open_dataset(tmp_path / "test.nc") xr.testing.assert_identical(original, roundtripped) From 83bbb73b968e60747098a7867ca11fa6ce283e17 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 11 Oct 2019 09:48:39 +0100 Subject: [PATCH 4/9] Remove redundant hypothesis config --- properties/test_netcdf_roundtrip.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/properties/test_netcdf_roundtrip.py b/properties/test_netcdf_roundtrip.py index 9f1813a52b4..ddba1fb6e6f 100644 --- a/properties/test_netcdf_roundtrip.py +++ b/properties/test_netcdf_roundtrip.py @@ -7,10 +7,6 @@ import xarray as xr -# Run for a while - arrays are a bigger search space than usual -settings.register_profile("ci", deadline=None) -settings.load_profile("ci") - an_array = npst.arrays( dtype=st.one_of( From 61bcc7ff4b3b1d23589b4f984c5dd10fb8d8f62f Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 11 Oct 2019 09:48:53 +0100 Subject: [PATCH 5/9] Clarifications around character strategy --- properties/test_netcdf_roundtrip.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/properties/test_netcdf_roundtrip.py b/properties/test_netcdf_roundtrip.py index ddba1fb6e6f..cc1bd3000ef 100644 --- a/properties/test_netcdf_roundtrip.py +++ b/properties/test_netcdf_roundtrip.py @@ -21,9 +21,11 @@ compatible_names = st.text( alphabet=st.characters( + # Limit characters to upper & lowercase letters and decimal digits whitelist_categories=("Ll", "Lu", "Nd"), # It looks like netCDF should allow unicode names, but removing # this causes a failure with 'ά' + # https://www.unidata.ucar.edu/software/netcdf/docs/netcdf_data_set_components.html#Permitted max_codepoint=255, ), min_size=1, From 67eaed1a92c6658641ac0eeb8b3b1fd2d0269441 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 11 Oct 2019 09:56:26 +0100 Subject: [PATCH 6/9] Use context manager to open & close netCDF file --- properties/test_netcdf_roundtrip.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/properties/test_netcdf_roundtrip.py b/properties/test_netcdf_roundtrip.py index cc1bd3000ef..deb0270e2ab 100644 --- a/properties/test_netcdf_roundtrip.py +++ b/properties/test_netcdf_roundtrip.py @@ -43,5 +43,5 @@ def test_netcdf_roundtrip(tmp_path, data, arr): original = xr.Dataset({"data": var}) original.to_netcdf(tmp_path / "test.nc") - roundtripped = xr.open_dataset(tmp_path / "test.nc") - xr.testing.assert_identical(original, roundtripped) + with xr.open_dataset(tmp_path / "test.nc") as roundtripped: + xr.testing.assert_identical(original, roundtripped) From 1b6a271524887478b492c193b474696312c0bbc7 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 11 Oct 2019 09:58:03 +0100 Subject: [PATCH 7/9] Add unicode & bytes dtype to netCDF roundtrip test --- properties/test_netcdf_roundtrip.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/properties/test_netcdf_roundtrip.py b/properties/test_netcdf_roundtrip.py index deb0270e2ab..59bf72e4efe 100644 --- a/properties/test_netcdf_roundtrip.py +++ b/properties/test_netcdf_roundtrip.py @@ -15,6 +15,8 @@ # NetCDF does not support float16 # https://www.unidata.ucar.edu/software/netcdf/docs/data_type.html npst.floating_dtypes(sizes=(32, 64)), + npst.byte_string_dtypes(), + npst.unicode_string_dtypes(), ), shape=npst.array_shapes(max_side=3), # max_side specified for performance ) From 4b932677334dd4dfd7ca69a52289cab32eb02ac4 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 11 Oct 2019 09:58:39 +0100 Subject: [PATCH 8/9] Add datetime64 & timedelta64 to netCDF roundtrip test --- properties/test_netcdf_roundtrip.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/properties/test_netcdf_roundtrip.py b/properties/test_netcdf_roundtrip.py index 59bf72e4efe..1f7a59bbc9c 100644 --- a/properties/test_netcdf_roundtrip.py +++ b/properties/test_netcdf_roundtrip.py @@ -17,6 +17,8 @@ npst.floating_dtypes(sizes=(32, 64)), npst.byte_string_dtypes(), npst.unicode_string_dtypes(), + npst.datetime64_dtypes(), + npst.timedelta64_dtypes(), ), shape=npst.array_shapes(max_side=3), # max_side specified for performance ) From fbeaf41971afe2b74378d7de4807575d033bdb24 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sat, 12 Oct 2019 10:27:56 +0100 Subject: [PATCH 9/9] Remove unused import --- properties/test_netcdf_roundtrip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/properties/test_netcdf_roundtrip.py b/properties/test_netcdf_roundtrip.py index 1f7a59bbc9c..aec2afb16b4 100644 --- a/properties/test_netcdf_roundtrip.py +++ b/properties/test_netcdf_roundtrip.py @@ -3,7 +3,7 @@ """ import hypothesis.extra.numpy as npst import hypothesis.strategies as st -from hypothesis import given, settings +from hypothesis import given import xarray as xr