-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added validate_order method #97
base: main
Are you sure you want to change the base?
Changes from all commits
a80feb6
3773d79
239c14f
b766665
5f7fd58
c44a41f
3057571
17adc9f
573b0e1
8520807
9323208
f43ae9f
de0d2a4
633b43b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1354,3 +1354,103 @@ def default(self, obj): | |
return obj.item() | ||
return obj.tolist() | ||
return json.JSONEncoder.default(self, obj) | ||
|
||
|
||
class OrderError(ValueError): | ||
... | ||
|
||
|
||
def validate_order(run_iterable): | ||
""" | ||
Validates the order of a Bluesky Run. | ||
|
||
Parameters | ||
--------- | ||
run_iterable: iterable | ||
A Bluesky run in the form of an iterable of name, doc pairs. | ||
""" | ||
datum_cache = {} | ||
resource_cache = {} | ||
descriptor_cache = {} | ||
last_event_time = {} | ||
stop = None | ||
start = None | ||
|
||
def event_check(event): | ||
# Check that descriptor doc is received before the first event of that | ||
# stream. | ||
if last_event_time.get(event['descriptor']) is None: | ||
if descriptor_cache.get(event['descriptor']) is None: | ||
raise OrderError("Descriptor was not received before the " | ||
"first event of the stream.") | ||
|
||
# For each stream check that events are in timestamp order. | ||
if last_event_time.get(event['descriptor']) is None: | ||
last_event_time[event['descriptor']] = event['time'] | ||
else: | ||
if event['time'] < last_event_time[event['descriptor']]: | ||
raise OrderError("Events out of order.") | ||
last_event_time[event['descriptor']] = event['time'] | ||
|
||
external_keys = {key for key, val | ||
in descriptor_cache[event['descriptor']]['data_keys'].items() | ||
if 'external' in val} | ||
|
||
# Check that the filled keys match the external keys defined in the | ||
# descriptor. | ||
if external_keys != set(event['filled'].keys()): | ||
raise ValueError("Filled keys do not match external_keys from " | ||
f"the descriptor. external_keys:{external_keys}, " | ||
f"filled_keys:{event['filled'].keys()}") | ||
|
||
# Check that for each datum_id in the event, the datum document was | ||
# received first. | ||
for key, value in event['data'].items(): | ||
if key in external_keys: | ||
if datum_cache.get(value) is None: | ||
raise OrderError(f"Datum document {value} not received " | ||
f"before event that references it. event:{event}") | ||
|
||
def datum_check(datum): | ||
# Check that the referenced resource is received first. | ||
if resource_cache.get(doc['resource']) is None: | ||
raise OrderError(f"Resource document {datum['resource']} was not " | ||
f"received before the datum that refrences it. " | ||
f"datum: {datum}") | ||
|
||
for name, doc in run_iterable: | ||
# Check that the start document is the first document. | ||
if not start: | ||
if name != 'start': | ||
raise OrderError("The first document of the run must be a start " | ||
"document, but the first document received was " | ||
f"{name},{doc}") | ||
|
||
# Check that the stop document is the last document. | ||
if stop: | ||
raise OrderError("The stop document must be the last document of " | ||
"the run. Documents were received following the " | ||
"stop document.") | ||
if name == 'start': | ||
if start: | ||
raise ValueError(f"A second start document was received. {doc}") | ||
else: | ||
start = doc | ||
if name == 'stop': | ||
stop = doc | ||
if name == 'resource': | ||
resource_cache[doc['uid']] = doc | ||
if name == 'descriptor': | ||
descriptor_cache[doc['uid']] = doc | ||
if name == 'datum': | ||
datum_cache[doc['datum_id']] = doc | ||
datum_check(doc) | ||
if name == 'datum_page': | ||
for datum in unpack_datum_page(doc): | ||
datum_cache[datum['datum_id']] = datum | ||
datum_check(datum) | ||
if name == 'event': | ||
event_check(doc) | ||
if name == 'event_page': | ||
for event in unpack_event_page(doc): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This does not address:
|
||
event_check(event) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you copy over the content from #98 here to explain what constraints this is enforcing?