Skip to content

Commit 36a079e

Browse files
committed
Merge pull request #3 from SiggyF/fedor-missing
Fedor missing
2 parents a1dce1a + 8f73fe9 commit 36a079e

File tree

2 files changed

+66
-8
lines changed

2 files changed

+66
-8
lines changed

mmi/__init__.py

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,38 @@
66

77
def send_array(socket, A, flags=0, copy=False, track=False, metadata=None):
88
"""send a numpy array with metadata over zmq"""
9-
md = dict(
10-
dtype=str(A.dtype),
11-
shape=A.shape,
12-
timestamp=datetime.datetime.now().isoformat()
13-
)
9+
10+
# create a metadata dictionary for the message
11+
md = {}
12+
# always add a timestamp
13+
md['timestamp'] = datetime.datetime.now().isoformat()
14+
15+
# copy extra metadata
1416
if metadata:
1517
md.update(metadata)
18+
19+
# if we don't have an array
1620
if A is None:
1721
# send only json
1822
socket.send_json(md, flags)
19-
else:
20-
# send json, followed by array
21-
socket.send_json(md, flags | zmq.SNDMORE)
23+
# and we're done
24+
return
25+
26+
# add array metadata
27+
md['dtype'] = str(A.dtype)
28+
md['shape'] = A.shape
29+
try:
30+
# If an array has a fill value assume it's an array with missings
31+
# store the fill_Value in the metadata and fill the array before sending.
32+
# asscalar should work for scalar, 0d array or nd array of size 1
33+
md['fill_value'] = np.asscalar(A.fill_value)
34+
A = A.filled()
35+
except AttributeError:
36+
# no masked array, nothing to do
37+
pass
38+
39+
# send json, followed by array
40+
socket.send_json(md, flags | zmq.SNDMORE)
2241
# Make a copy if required and pass along the buffer
2342
msg = buffer(np.ascontiguousarray(A))
2443
socket.send(msg, flags, copy=copy, track=track)
@@ -33,6 +52,8 @@ def recv_array(socket, flags=0, copy=False, track=False):
3352
buf = buffer(msg)
3453
A = np.frombuffer(buf, dtype=md['dtype'])
3554
A = A.reshape(md['shape'])
55+
if 'fill_value' in md:
56+
A = np.ma.masked_equal(A, md['fill_value'])
3657
else:
3758
# No array expected
3859
A = None

tests/test_simple.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
ctx = zmq.Context()
1111
class TestRecv(unittest.TestCase):
1212
def test_sndrcv(self):
13+
"""send an array"""
1314
A = np.array([1,2,3])
1415
req = ctx.socket(zmq.REQ)
1516
req.connect('tcp://localhost:9002')
@@ -19,5 +20,41 @@ def test_sndrcv(self):
1920
B, metadata = mmi.recv_array(rep)
2021
numpy.testing.assert_array_equal(A, B)
2122

23+
def test_metadata_only(self):
24+
"""send a message with only metadata"""
25+
req = ctx.socket(zmq.REQ)
26+
req.connect('tcp://localhost:9002')
27+
rep = ctx.socket(zmq.REP)
28+
rep.bind('tcp://*:9002')
29+
mmi.send_array(req, A=None)
30+
_, metadata = mmi.recv_array(rep)
31+
self.assertTrue('timestamp' in metadata)
32+
33+
def test_missing(self):
34+
"""send an array with missing data"""
35+
A = np.array([1, 2, 3, 4])
36+
A = np.ma.masked_less(A, 2)
37+
req = ctx.socket(zmq.REQ)
38+
req.connect('tcp://localhost:9002')
39+
rep = ctx.socket(zmq.REP)
40+
rep.bind('tcp://*:9002')
41+
mmi.send_array(req, A)
42+
B, metadata = mmi.recv_array(rep)
43+
numpy.testing.assert_array_equal(A, B)
44+
45+
def test_missing_scalar(self):
46+
"""send an array with missing data as a scalar"""
47+
A = np.array([1, 2, 3, 4])
48+
A = np.ma.masked_less(A, 2)
49+
# test if it works if we use a numpy scalar
50+
A.fill_value = np.int32(9999)
51+
req = ctx.socket(zmq.REQ)
52+
req.connect('tcp://localhost:9002')
53+
rep = ctx.socket(zmq.REP)
54+
rep.bind('tcp://*:9002')
55+
mmi.send_array(req, A)
56+
B, metadata = mmi.recv_array(rep)
57+
numpy.testing.assert_array_equal(A, B)
58+
2259

2360

0 commit comments

Comments
 (0)