diff --git a/pipeline/fiftyone_pipeline_core/src/fiftyone_pipeline_core/flowdata.py b/pipeline/fiftyone_pipeline_core/src/fiftyone_pipeline_core/flowdata.py index c6f83c7c..914d7596 100644 --- a/pipeline/fiftyone_pipeline_core/src/fiftyone_pipeline_core/flowdata.py +++ b/pipeline/fiftyone_pipeline_core/src/fiftyone_pipeline_core/flowdata.py @@ -203,7 +203,8 @@ def set_element_data(self, element_data): """ - self.data[element_data.flow_element.datakey] = element_data + # Kept under the data key in lower case, which is how get reads it. + self.data[element_data.flow_element.datakey.lower()] = element_data def set_error(self, flow_error): diff --git a/pipeline/fiftyone_pipeline_core/src/fiftyone_pipeline_core/jsonbundler.py b/pipeline/fiftyone_pipeline_core/src/fiftyone_pipeline_core/jsonbundler.py index 9f2a8ca7..4262d740 100644 --- a/pipeline/fiftyone_pipeline_core/src/fiftyone_pipeline_core/jsonbundler.py +++ b/pipeline/fiftyone_pipeline_core/src/fiftyone_pipeline_core/jsonbundler.py @@ -103,7 +103,7 @@ def process_internal(self, flowdata): if len(delayed_evidence_properties_list): delayed_evidence_properties[propertykey] = list(map(lambda x: - flow_element.datakey + '.' + x, delayed_evidence_properties_list)) + flow_element.datakey.lower() + '.' + x, delayed_evidence_properties_list)) self.property_cache[flow_element.datakey] = { @@ -115,7 +115,7 @@ def process_internal(self, flowdata): # Create empty area for FlowElement properties to go - output[flow_element.datakey] = {} + output[flow_element.datakey.lower()] = {} for propertykey, propertymeta in properties.items(): value = None @@ -125,13 +125,13 @@ def process_internal(self, flowdata): if propertykey in property_cache["delayExecutionList"]: - output[flow_element.datakey][propertykey.lower() + "delayexecution"] = True + output[flow_element.datakey.lower()][propertykey.lower() + "delayexecution"] = True # Check if property has any delayed execution evidence properties and set in JSON if yes if propertykey in property_cache["evidenceProperties"]: - output[flow_element.datakey][propertykey.lower() + 'evidenceproperties'] = property_cache["evidenceProperties"][propertykey] + output[flow_element.datakey.lower()][propertykey.lower() + 'evidenceproperties'] = property_cache["evidenceProperties"][propertykey] try: diff --git a/pipeline/fiftyone_pipeline_core/tests/test_jsonbundler_lower_case.py b/pipeline/fiftyone_pipeline_core/tests/test_jsonbundler_lower_case.py new file mode 100644 index 00000000..028eac4a --- /dev/null +++ b/pipeline/fiftyone_pipeline_core/tests/test_jsonbundler_lower_case.py @@ -0,0 +1,69 @@ + +""" +The JSON Builder writes the key of each top-level entry and of each sub-entry, +including the meta-Property suffixes, in lower case, apart from +javascriptProperties, as the JSON Builder specification says. +""" + +import unittest + +from fiftyone_pipeline_core.aspectproperty_value import AspectPropertyValue +from fiftyone_pipeline_core.elementdata_dictionary import ElementDataDictionary +from fiftyone_pipeline_core.flowelement import FlowElement +from fiftyone_pipeline_core.pipelinebuilder import PipelineBuilder + + +class MixedCaseElement(FlowElement): + + def __init__(self): + super(MixedCaseElement, self).__init__() + self.datakey = "MixedCase" + self.properties = { + "DelayedProp": { + "name": "DelayedProp", "type": "string", + "delayexecution": True}, + "OtherProp": { + "name": "OtherProp", "type": "string", + "evidenceproperties": ["delayedprop"]}, + "EmptyProp": {"name": "EmptyProp", "type": "string"}} + + def process_internal(self, flowdata): + # Set as a real element sets it, under its mixed case data key. + flowdata.set_element_data(ElementDataDictionary( + self, {"DelayedProp": "a", "OtherProp": "b", + "EmptyProp": AspectPropertyValue( + no_value_message="No value")})) + + +class JsonBuilderLowerCaseTests(unittest.TestCase): + + def process(self): + pipeline = PipelineBuilder({}).add(MixedCaseElement()).build() + self.addCleanup(pipeline.close) + flowdata = pipeline.create_flowdata() + flowdata.process() + return flowdata.jsonbundler.json + + def test_every_key_is_lower_case_but_javascript_properties(self): + json = self.process() + self.assertIn("javascriptProperties", json) + self.assertIn("mixedcase", json) + for key, value in json.items(): + if key == "javascriptProperties": + continue + self.assertEqual(key.lower(), key) + for sub_key in value: + self.assertEqual(sub_key.lower(), sub_key, sub_key) + + def test_the_meta_property_keys_are_lower_case(self): + section = self.process()["mixedcase"] + self.assertTrue(section["delayedpropdelayexecution"]) + self.assertIn("otherpropevidenceproperties", section) + self.assertEqual("No value", section["emptypropnullreason"]) + self.assertIsNone(section["emptyprop"]) + self.assertEqual("a", section["delayedprop"]) + self.assertEqual("b", section["otherprop"]) + + +if __name__ == "__main__": + unittest.main()