|
26 | 26 | import collections |
27 | 27 | import io |
28 | 28 | import json |
| 29 | +import os |
29 | 30 | import pickle |
30 | 31 | import pprint |
31 | 32 | import struct |
| 33 | +import tempfile |
| 34 | +import unittest |
32 | 35 | from unittest.mock import patch |
33 | 36 |
|
34 | 37 | import msgpack |
|
41 | 44 | import tskit.metadata as metadata |
42 | 45 |
|
43 | 46 |
|
| 47 | +class TestMetadataRoundTrip(unittest.TestCase): |
| 48 | + """ |
| 49 | + Tests that we can encode metadata under various formats. |
| 50 | + """ |
| 51 | + |
| 52 | + def setUp(self): |
| 53 | + fd, self.temp_file = tempfile.mkstemp(prefix="msp_meta_test_") |
| 54 | + os.close(fd) |
| 55 | + |
| 56 | + def tearDown(self): |
| 57 | + os.unlink(self.temp_file) |
| 58 | + |
| 59 | + def test_json(self): |
| 60 | + ts = msprime.simulate(10, random_seed=1) |
| 61 | + tables = ts.dump_tables() |
| 62 | + nodes = tables.nodes |
| 63 | + # For each node, we create some Python metadata that can be JSON encoded. |
| 64 | + metadata = [ |
| 65 | + {"one": j, "two": 2 * j, "three": list(range(j))} for j in range(len(nodes)) |
| 66 | + ] |
| 67 | + encoded, offset = tskit.pack_strings(map(json.dumps, metadata)) |
| 68 | + nodes.set_columns( |
| 69 | + flags=nodes.flags, |
| 70 | + time=nodes.time, |
| 71 | + population=nodes.population, |
| 72 | + metadata_offset=offset, |
| 73 | + metadata=encoded, |
| 74 | + ) |
| 75 | + assert np.array_equal(nodes.metadata_offset, offset) |
| 76 | + assert np.array_equal(nodes.metadata, encoded) |
| 77 | + ts1 = tables.tree_sequence() |
| 78 | + for j, node in enumerate(ts1.nodes()): |
| 79 | + decoded_metadata = json.loads(node.metadata.decode()) |
| 80 | + assert decoded_metadata == metadata[j] |
| 81 | + ts1.dump(self.temp_file) |
| 82 | + ts2 = tskit.load(self.temp_file) |
| 83 | + assert ts1.tables.nodes == ts2.tables.nodes |
| 84 | + |
| 85 | + def test_pickle(self): |
| 86 | + ts = msprime.simulate(10, random_seed=1) |
| 87 | + tables = ts.dump_tables() |
| 88 | + # For each node, we create some Python metadata that can be pickled |
| 89 | + metadata = [ |
| 90 | + {"one": j, "two": 2 * j, "three": list(range(j))} |
| 91 | + for j in range(ts.num_nodes) |
| 92 | + ] |
| 93 | + encoded, offset = tskit.pack_bytes(list(map(pickle.dumps, metadata))) |
| 94 | + tables.nodes.set_columns( |
| 95 | + flags=tables.nodes.flags, |
| 96 | + time=tables.nodes.time, |
| 97 | + population=tables.nodes.population, |
| 98 | + metadata_offset=offset, |
| 99 | + metadata=encoded, |
| 100 | + ) |
| 101 | + assert np.array_equal(tables.nodes.metadata_offset, offset) |
| 102 | + assert np.array_equal(tables.nodes.metadata, encoded) |
| 103 | + ts1 = tables.tree_sequence() |
| 104 | + for j, node in enumerate(ts1.nodes()): |
| 105 | + decoded_metadata = pickle.loads(node.metadata) |
| 106 | + assert decoded_metadata == metadata[j] |
| 107 | + ts1.dump(self.temp_file) |
| 108 | + ts2 = tskit.load(self.temp_file) |
| 109 | + assert ts1.tables.nodes == ts2.tables.nodes |
| 110 | + |
| 111 | + |
44 | 112 | class ExampleMetadata: |
45 | 113 | """ |
46 | 114 | Simple class that we can pickle/unpickle in metadata. |
|
0 commit comments