Skip to content

Commit

Permalink
Add custom json encoder and decoder
Browse files Browse the repository at this point in the history
  • Loading branch information
constantinpape committed Jan 23, 2020
1 parent 994f244 commit 2741da2
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 2 deletions.
3 changes: 3 additions & 0 deletions zarr/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ def encode_fill_value(v, dtype):
if v is None:
return v
if dtype.kind == 'f':
# these cases are handled in the ZarrJsonEncoder now,
# but there may be cases where the metadata was not parsed
# with this encoder (?), so better to leave it here
if np.isnan(v):
return 'NaN'
elif np.isposinf(v):
Expand Down
13 changes: 13 additions & 0 deletions zarr/tests/test_attrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import pytest

import numpy as np
from zarr.attrs import Attributes
from zarr.tests.util import CountingDict

Expand Down Expand Up @@ -218,3 +219,15 @@ def test_caching_off(self):
assert 'spam' not in a
assert 10 == store.counter['__getitem__', 'attrs']
assert 3 == store.counter['__setitem__', 'attrs']

def test_special_values(self):
a = self.init_attributes(dict())

a['nan'] = np.nan
assert np.isnan(a['nan'])

a['pinf'] = np.PINF
assert np.isposinf(a['pinf'])

a['ninf'] = np.NINF
assert np.isneginf(a['ninf'])
33 changes: 31 additions & 2 deletions zarr/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,44 @@
}


class ZarrJsonEncoder(JsonEncoder):
"""Encode json input
"""
def default(self, obj):
if np.isnan(obj):
return "NaN"
elif np.isposinf(obj):
return "Infinity"
elif np.isneginf(obj):
return "-Infinity"
# we could also allow for passing numpy dtypes:
# if isinstance(obj, np.dtype):
# return obj.item()
return super().default(obj)


class ZarrJsonDecoder(JsonEncoder):
"""Decode json input
"""
def default(self, obj):
if obj == "NaN":
return np.nan
elif obj == "Infinity":
return np.PINF
elif obj == "-Infinity":
return np.NINF
return super().default(obj)


def json_dumps(o):
"""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=ZarrJsonEncoder).encode('ascii')


def json_loads(s):
"""Read JSON in a consistent way."""
return json.loads(ensure_text(s, 'ascii'))
return json.loads(ensure_text(s, 'ascii'), cls=ZarrJsonDecoder)


def normalize_shape(shape):
Expand Down

0 comments on commit 2741da2

Please sign in to comment.