From 76c9125fe467eda0bea4c30592dd214aca70a52d Mon Sep 17 00:00:00 2001 From: Eric Prestat Date: Tue, 11 Jan 2022 13:45:20 +0000 Subject: [PATCH 1/3] Add numpy encoder class for json.dumps and add test --- zarr/tests/test_creation.py | 5 +++++ zarr/tests/test_util.py | 15 +++++++++++++-- zarr/util.py | 15 ++++++++++++++- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/zarr/tests/test_creation.py b/zarr/tests/test_creation.py index 0ec551ba4e..60d7c91ca2 100644 --- a/zarr/tests/test_creation.py +++ b/zarr/tests/test_creation.py @@ -540,3 +540,8 @@ def test_create_read_only(): assert z.read_only with pytest.raises(PermissionError): z[:] = 42 + + +def test_json_dumps_chunks_numpy_dtype(): + z = zeros((10,), chunks=(np.int64(2),)) + assert np.all(z[...] == 0) diff --git a/zarr/tests/test_util.py b/zarr/tests/test_util.py index efe8e66341..e2ae6330b7 100644 --- a/zarr/tests/test_util.py +++ b/zarr/tests/test_util.py @@ -4,8 +4,10 @@ import numpy as np import pytest -from zarr.util import (all_equal, flatten, guess_chunks, human_readable_size, info_html_report, - info_text_report, is_total_slice, normalize_chunks, +from zarr.core import Array +from zarr.util import (all_equal, flatten, guess_chunks, human_readable_size, + info_html_report, info_text_report, is_total_slice, + json_dumps, normalize_chunks, normalize_dimension_separator, normalize_fill_value, normalize_order, normalize_resize_args, normalize_shape, retry_call, @@ -238,3 +240,12 @@ def test_all_equal(): # all_equal(None, *) always returns False assert not all_equal(None, np.array([None, None])) assert not all_equal(None, np.array([None, 10])) + + +def test_json_dumps_numpy_dtype(): + assert json_dumps(np.int64(0)) == json_dumps(0) + assert json_dumps(np.float64(0)) == json_dumps(float(0)) + assert json_dumps(np.array([0, 1])) == json_dumps([0, 1]) + # Check that we raise the error of the superclass for unsupported object + with pytest.raises(TypeError): + json_dumps(Array) diff --git a/zarr/util.py b/zarr/util.py index 04d350a68d..153253759e 100644 --- a/zarr/util.py +++ b/zarr/util.py @@ -33,10 +33,23 @@ def flatten(arg: Iterable) -> Iterable: } +class NumpyEncoder(json.JSONEncoder): + + def default(self, o): + # See json.JSONEncoder.default docstring for explanation + if isinstance(o, np.integer): + return int(o) + if isinstance(o, np.floating): + return float(o) + if isinstance(o, np.ndarray): + return o.tolist() + return json.JSONEncoder.default(self, o) + + def json_dumps(o: Any) -> bytes: """Write JSON in a consistent, human-readable way.""" return json.dumps(o, indent=4, sort_keys=True, ensure_ascii=True, - separators=(',', ': ')).encode('ascii') + separators=(',', ': '), cls=NumpyEncoder).encode('ascii') def json_loads(s: str) -> Dict[str, Any]: From fd37e1cfa3e20940aa5c1d2690ef32e87c4f88bf Mon Sep 17 00:00:00 2001 From: Eric Prestat Date: Sat, 15 Jan 2022 11:43:02 +0000 Subject: [PATCH 2/3] Use numbers instead of numpy module --- zarr/tests/test_util.py | 3 +-- zarr/util.py | 11 +++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/zarr/tests/test_util.py b/zarr/tests/test_util.py index e2ae6330b7..e9e1786abe 100644 --- a/zarr/tests/test_util.py +++ b/zarr/tests/test_util.py @@ -244,8 +244,7 @@ def test_all_equal(): def test_json_dumps_numpy_dtype(): assert json_dumps(np.int64(0)) == json_dumps(0) - assert json_dumps(np.float64(0)) == json_dumps(float(0)) - assert json_dumps(np.array([0, 1])) == json_dumps([0, 1]) + assert json_dumps(np.float32(0)) == json_dumps(float(0)) # Check that we raise the error of the superclass for unsupported object with pytest.raises(TypeError): json_dumps(Array) diff --git a/zarr/util.py b/zarr/util.py index 153253759e..c0b5d4ff04 100644 --- a/zarr/util.py +++ b/zarr/util.py @@ -33,23 +33,22 @@ def flatten(arg: Iterable) -> Iterable: } -class NumpyEncoder(json.JSONEncoder): +class NumberEncoder(json.JSONEncoder): def default(self, o): # See json.JSONEncoder.default docstring for explanation - if isinstance(o, np.integer): + # This is necessary to encode numpy dtype + if isinstance(o, numbers.Integral): return int(o) - if isinstance(o, np.floating): + if isinstance(o, numbers.Real): return float(o) - if isinstance(o, np.ndarray): - return o.tolist() return json.JSONEncoder.default(self, o) def json_dumps(o: Any) -> bytes: """Write JSON in a consistent, human-readable way.""" return json.dumps(o, indent=4, sort_keys=True, ensure_ascii=True, - separators=(',', ': '), cls=NumpyEncoder).encode('ascii') + separators=(',', ': '), cls=NumberEncoder).encode('ascii') def json_loads(s: str) -> Dict[str, Any]: From 7cc40c30f765e5bb9f9c5b94ca02049129f5d84d Mon Sep 17 00:00:00 2001 From: Eric Prestat Date: Fri, 15 Apr 2022 09:56:40 +0100 Subject: [PATCH 3/3] Add entry to release note --- docs/release.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/release.rst b/docs/release.rst index 13c2f20d2c..7a5cf51db7 100644 --- a/docs/release.rst +++ b/docs/release.rst @@ -14,6 +14,9 @@ Bug fixes value when empty chunks are read back in. By :user:`Vyas Ramasubramani `; :issue:`965`. +* Add number encoder for ``json.dumps`` to support numpy intergers in + ``chunks`` arguments. By :user:`Eric Prestat ` :issue:`697`. + .. _release_2.11.1: 2.11.1