Skip to content

Commit 48aa41d

Browse files
authored
Collect JSON utility functions (#430)
* Move `ensure_text_type` to `zarr.util` As `ensure_text_type` is a more general utility function, go ahead and move it over to `zarr.util` and drop it from `zarr.meta`. Though make sure to import it into `zarr.meta` so that it can still be used there. * Move `json_dumps` to `zarr.util` As `json_dumps` has broader use than just for metdata (e.g. attributes would also benefit from it), this moves `json_dumps` to `zarr.util`. * Move `json_loads` to `zarr.util` As `json_loads` is more generally useful than just parsing metadata, move it over to `zarr.util`. Though ensure it is still imported in `zarr.meta`. * Use `json_loads` in `ConsolidatedMetadataStore` Should ensure that the `ConsolidatedMetadataStore` is able to handle loading JSON data in a standard way. * Use `json_dumps` to serialize attributes * Handle `encode` within `json_dumps` As every use of `json_dumps` is followed by a call to `encode` to convert the string to bytes, go ahead and incorporate this step in `json_dumps`. Should make it a bit easier to use. * Drop `encode` from `json_dumps` output As the `encode` step is now part of `json_dumps`, remove that step when using the `json_dumps` function. * Drop unneeded intermediates in `json_dumps` usage After moving `encode` within `json_dumps`, there were intermediate variables left over that weren't really needed. This drops them. * Update release note on JSON reading and writing
1 parent a7546b7 commit 48aa41d

File tree

7 files changed

+38
-45
lines changed

7 files changed

+38
-45
lines changed

docs/release.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ Release notes
99
Bug fixes
1010
~~~~~~~~~
1111

12-
* Coerce data to text for JSON parsing.
13-
By :user:`John Kirkham <jakirkham>`; :issue:`429`
12+
* Add and use utility functions to simplify reading and writing JSON.
13+
By :user:`John Kirkham <jakirkham>`; :issue:`429`, :issue:`430`
1414

1515

1616
.. _release_2.3.1:

zarr/attrs.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# -*- coding: utf-8 -*-
22
from __future__ import absolute_import, print_function, division
3-
import json
43
from collections import MutableMapping
54

65

76
from zarr.errors import PermissionError
87
from zarr.meta import parse_metadata
8+
from zarr.util import json_dumps
99

1010

1111
class Attributes(MutableMapping):
@@ -113,9 +113,7 @@ def put(self, d):
113113
self._write_op(self._put_nosync, d)
114114

115115
def _put_nosync(self, d):
116-
s = json.dumps(d, indent=4, sort_keys=True, ensure_ascii=True,
117-
separators=(',', ': '))
118-
self.store[self.key] = s.encode('ascii')
116+
self.store[self.key] = json_dumps(d)
119117
if self.cache:
120118
self._cached_asdict = d
121119

zarr/convenience.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1125,7 +1125,7 @@ def is_zarr_key(key):
11251125
for key in store if is_zarr_key(key)
11261126
}
11271127
}
1128-
store[metadata_key] = json_dumps(out).encode()
1128+
store[metadata_key] = json_dumps(out)
11291129
return open_consolidated(store, metadata_key=metadata_key)
11301130

11311131

zarr/meta.py

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,19 @@
11
# -*- coding: utf-8 -*-
22
from __future__ import absolute_import, print_function, division
3-
import json
43
import base64
5-
import codecs
64

75

86
import numpy as np
9-
from numcodecs.compat import ensure_contiguous_ndarray
107

118

12-
from zarr.compat import PY2, Mapping, text_type
9+
from zarr.compat import PY2, Mapping
1310
from zarr.errors import MetadataError
11+
from zarr.util import json_dumps, json_loads
1412

1513

1614
ZARR_FORMAT = 2
1715

1816

19-
def ensure_text_type(s):
20-
if not isinstance(s, text_type):
21-
s = ensure_contiguous_ndarray(s)
22-
s = codecs.decode(s, 'ascii')
23-
return s
24-
25-
26-
def json_dumps(o):
27-
"""Write JSON in a consistent, human-readable way."""
28-
return json.dumps(o, indent=4, sort_keys=True, ensure_ascii=True,
29-
separators=(',', ': '))
30-
31-
32-
def json_loads(s):
33-
"""Read JSON in a consistent way."""
34-
return json.loads(ensure_text_type(s))
35-
36-
3717
def parse_metadata(s):
3818

3919
# Here we allow that a store may return an already-parsed metadata object,
@@ -95,9 +75,7 @@ def encode_array_metadata(meta):
9575
order=meta['order'],
9676
filters=meta['filters'],
9777
)
98-
s = json_dumps(meta)
99-
b = s.encode('ascii')
100-
return b
78+
return json_dumps(meta)
10179

10280

10381
def encode_dtype(d):
@@ -142,9 +120,7 @@ def encode_group_metadata(meta=None):
142120
meta = dict(
143121
zarr_format=ZARR_FORMAT,
144122
)
145-
s = json_dumps(meta)
146-
b = s.encode('ascii')
147-
return b
123+
return json_dumps(meta)
148124

149125

150126
FLOAT_FILLS = {

zarr/n5.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,14 @@ def __getitem__(self, key):
7171
key = key.replace(zarr_group_meta_key, n5_attrs_key)
7272
value = group_metadata_to_zarr(self._load_n5_attrs(key))
7373

74-
return json_dumps(value).encode('ascii')
74+
return json_dumps(value)
7575

7676
elif key.endswith(zarr_array_meta_key):
7777

7878
key = key.replace(zarr_array_meta_key, n5_attrs_key)
7979
value = array_metadata_to_zarr(self._load_n5_attrs(key))
8080

81-
return json_dumps(value).encode('ascii')
81+
return json_dumps(value)
8282

8383
elif key.endswith(zarr_attrs_key):
8484

@@ -88,7 +88,7 @@ def __getitem__(self, key):
8888
if len(value) == 0:
8989
raise KeyError(key)
9090
else:
91-
return json_dumps(value).encode('ascii')
91+
return json_dumps(value)
9292

9393
elif is_chunk_key(key):
9494

@@ -105,7 +105,7 @@ def __setitem__(self, key, value):
105105
n5_attrs = self._load_n5_attrs(key)
106106
n5_attrs.update(**group_metadata_to_n5(json_loads(value)))
107107

108-
value = json_dumps(n5_attrs).encode('ascii')
108+
value = json_dumps(n5_attrs)
109109

110110
elif key.endswith(zarr_array_meta_key):
111111

@@ -114,7 +114,7 @@ def __setitem__(self, key, value):
114114
n5_attrs = self._load_n5_attrs(key)
115115
n5_attrs.update(**array_metadata_to_n5(json_loads(value)))
116116

117-
value = json_dumps(n5_attrs).encode('ascii')
117+
value = json_dumps(n5_attrs)
118118

119119
elif key.endswith(zarr_attrs_key):
120120

@@ -135,7 +135,7 @@ def __setitem__(self, key, value):
135135
# add new user attributes
136136
n5_attrs.update(**zarr_attrs)
137137

138-
value = json_dumps(n5_attrs).encode('ascii')
138+
value = json_dumps(n5_attrs)
139139

140140
elif is_chunk_key(key):
141141

zarr/storage.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,14 @@
2626
import errno
2727
import re
2828
import sys
29-
import json
3029
import multiprocessing
3130
from pickle import PicklingError
3231
from threading import Lock, RLock
3332
import glob
3433
import warnings
3534

3635

37-
from zarr.util import (normalize_shape, normalize_chunks, normalize_order,
36+
from zarr.util import (json_loads, normalize_shape, normalize_chunks, normalize_order,
3837
normalize_storage_path, buffer_size,
3938
normalize_fill_value, nolock, normalize_dtype)
4039
from zarr.meta import encode_array_metadata, encode_group_metadata
@@ -2458,7 +2457,7 @@ def __init__(self, store, metadata_key='.zmetadata'):
24582457
d = store[metadata_key].decode() # pragma: no cover
24592458
else: # pragma: no cover
24602459
d = store[metadata_key]
2461-
meta = json.loads(d)
2460+
meta = json_loads(d)
24622461

24632462
# check format of consolidated metadata
24642463
consolidated_format = meta.get('zarr_consolidated_format', None)

zarr/util.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# -*- coding: utf-8 -*-
22
from __future__ import absolute_import, print_function, division
33
from textwrap import TextWrapper, dedent
4+
import codecs
5+
import json
46
import numbers
57
import uuid
68
import inspect
@@ -9,7 +11,7 @@
911
from asciitree import BoxStyle, LeftAligned
1012
from asciitree.traversal import Traversal
1113
import numpy as np
12-
from numcodecs.compat import ensure_ndarray
14+
from numcodecs.compat import ensure_ndarray, ensure_contiguous_ndarray
1315
from numcodecs.registry import codec_registry
1416

1517

@@ -24,6 +26,24 @@
2426
}
2527

2628

29+
def ensure_text_type(s):
30+
if not isinstance(s, text_type):
31+
s = ensure_contiguous_ndarray(s)
32+
s = codecs.decode(s, 'ascii')
33+
return s
34+
35+
36+
def json_dumps(o):
37+
"""Write JSON in a consistent, human-readable way."""
38+
return json.dumps(o, indent=4, sort_keys=True, ensure_ascii=True,
39+
separators=(',', ': ')).encode('ascii')
40+
41+
42+
def json_loads(s):
43+
"""Read JSON in a consistent way."""
44+
return json.loads(ensure_text_type(s))
45+
46+
2747
def normalize_shape(shape):
2848
"""Convenience function to normalize the `shape` argument."""
2949

0 commit comments

Comments
 (0)