Skip to content

Commit 2777cbb

Browse files
committed
ENH #137 add utils.export_json() and test
1 parent 15732c7 commit 2777cbb

File tree

3 files changed

+134
-0
lines changed

3 files changed

+134
-0
lines changed

apstools/utils.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
~EmailNotifications
99
~ExcelDatabaseFileBase
1010
~ExcelDatabaseFileGeneric
11+
~export_json
1112
~ipython_profile_name
1213
~pairwise
1314
~print_snapshot_list
@@ -31,6 +32,9 @@
3132
from collections import OrderedDict
3233
import datetime
3334
from email.mime.text import MIMEText
35+
from event_model import NumpyEncoder
36+
from io import StringIO
37+
import json
3438
import logging
3539
import math
3640
import os
@@ -40,6 +44,7 @@
4044
import smtplib
4145
import subprocess
4246
import time
47+
import zipfile
4348

4449
from .plans import run_in_thread
4550

@@ -535,3 +540,50 @@ def print_snapshot_list(db, **search_criteria):
535540
n = len(list(h.start.keys()))
536541
t.addRow((i, uid, h.start["iso8601"], n, h.start["purpose"]))
537542
print(t)
543+
544+
545+
def export_json(headers, filename, zipfilename=None):
546+
"""
547+
write a list of headers (all documents) to a file
548+
549+
PARAMETERS
550+
551+
headers : list(headers) or `databroker._core.Results` object
552+
list of databroker headers as returned from `db(...search criteria...)`
553+
filename : str
554+
name of file into which to write JSON
555+
zipfilename : str or None
556+
name of ZIP file container of `filename`
557+
(if None, do not ZIP `filename`)
558+
559+
EXAMPLE::
560+
561+
from databroker import Broker
562+
db = Broker.named("mongodb_config")
563+
headers = db(plan_name="count", since="2019-04-01")
564+
565+
export_json(
566+
headers,
567+
"data.json",
568+
zipfilename="bluesky_data.zip")
569+
570+
EXAMPLE: READ THE ZIP FILE::
571+
572+
with zipfile.ZipFile(zipfilename, "r") as fp:
573+
buf = fp.read(filename).decode("utf-8")
574+
header_dict = json.loads(buf)
575+
576+
"""
577+
datasets = [list(h.documents()) for h in headers]
578+
# for h in headers:
579+
# uid = h.start["uid"]
580+
# datasets[uid] = list(h.documents())
581+
582+
json_docs = json.dumps(datasets, cls=NumpyEncoder, indent=2)
583+
if zipfilename is None:
584+
with open(filename, "w") as fp:
585+
fp.write(json_docs)
586+
else:
587+
with zipfile.ZipFile(zipfilename, "w", allowZip64=True) as fp:
588+
fp.writestr(filename, json_docs, compress_type=zipfile.ZIP_LZMA)
589+

tests/__main__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ def suite(*args, **kw):
1414

1515
import test_simple
1616
import test_filewriter
17+
import test_export_json
1718
# import test_excel
1819
test_list = [
1920
test_simple,
2021
test_filewriter,
22+
test_export_json,
2123
# test_excel
2224
]
2325

tests/test_export_json.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
2+
"""
3+
unit tests for the SPEC filewriter
4+
"""
5+
6+
import json
7+
import os
8+
import shutil
9+
import sys
10+
import tempfile
11+
import unittest
12+
import zipfile
13+
14+
15+
_test_path = os.path.dirname(__file__)
16+
_path = os.path.join(_test_path, '..')
17+
if _path not in sys.path:
18+
sys.path.insert(0, _path)
19+
20+
from apstools.utils import export_json
21+
22+
23+
class Test_ExportZippedJson(unittest.TestCase):
24+
25+
def setUp(self):
26+
self.tempdir = tempfile.mkdtemp()
27+
28+
def tearDown(self):
29+
if os.path.exists(self.tempdir):
30+
shutil.rmtree(self.tempdir, ignore_errors=True)
31+
32+
def test_writer_default_name(self):
33+
from databroker import Broker
34+
db = Broker.named("mongodb_config")
35+
headers = db(plan_name="count")
36+
headers = list(headers)[0:1]
37+
38+
filename = os.path.join(self.tempdir, "export1.txt")
39+
export_json(headers, filename=filename)
40+
self.assertTrue(os.path.exists(filename), f"wrote to requested {filename}")
41+
42+
filename = "export2.txt"
43+
zipfilename = os.path.join(self.tempdir, "export2.zip")
44+
export_json(headers, filename, zipfilename=zipfilename)
45+
self.assertFalse(os.path.exists(filename), f"did not write to {filename}")
46+
self.assertTrue(
47+
os.path.exists(zipfilename),
48+
f"wrote to requested ZIP {zipfilename}")
49+
with zipfile.ZipFile(zipfilename, "r") as fp:
50+
self.assertIn(filename, fp.namelist(), "found JSON test data")
51+
buf = fp.read(filename).decode("utf-8")
52+
testdata = json.loads(buf)
53+
self.assertEqual(len(testdata), 1, "ZIP file contains one dataset")
54+
dataset = testdata[0]
55+
self.assertGreater(len(dataset), 1, "dataset contains more than one document")
56+
tag, doc = dataset[0]
57+
self.assertEqual(tag, "start", "found start document")
58+
self.assertNotEqual(doc.get("plan_name"), None, "found a start document by duck type")
59+
self.assertNotEqual(doc.get("uid"), None, "found a uid document")
60+
self.assertEqual(
61+
doc["uid"],
62+
headers[0].start["uid"],
63+
"found matching start document"
64+
)
65+
66+
67+
def suite(*args, **kw):
68+
test_list = [
69+
Test_ExportZippedJson,
70+
]
71+
72+
test_suite = unittest.TestSuite()
73+
for test_case in test_list:
74+
test_suite.addTest(unittest.makeSuite(test_case))
75+
return test_suite
76+
77+
78+
if __name__ == "__main__":
79+
runner=unittest.TextTestRunner()
80+
runner.run(suite())

0 commit comments

Comments
 (0)