def test_nested_serialization(): """Create a bunch of nested objects and make sure that nothing breaks.""" # helper def make_ingredient(material: MaterialRun): return IngredientRun(name=material.name, material=material) icing = ProcessRun(name="Icing") cake = MaterialRun(name='Final cake', process=icing) cake.process.ingredients.append(make_ingredient(MaterialRun('Baked Cake'))) cake.process.ingredients.append(make_ingredient(MaterialRun('Frosting'))) baked = cake.process.ingredients[0].material baked.process = ProcessRun(name='Baking') baked.process.ingredients.append(make_ingredient(MaterialRun('Batter'))) batter = baked.process.ingredients[0].material batter.process = ProcessRun(name='Mixing batter') batter.process.ingredients.append( make_ingredient(material=MaterialRun('Butter'))) batter.process.ingredients.append( make_ingredient(material=MaterialRun('Sugar'))) batter.process.ingredients.append( make_ingredient(material=MaterialRun('Flour'))) batter.process.ingredients.append( make_ingredient(material=MaterialRun('Milk'))) cake.dump()
def test_object_pointer_serde(): """Test that an object can point to another object, and that this survives serde.""" baking = ProcessRun("Bake a cake") cake = MaterialRun("A cake", process=baking) reconstituted_cake = MaterialRun.build(cake.dump()) assert isinstance(reconstituted_cake.process, ProcessRun) assert isinstance(reconstituted_cake.process.output_material, MaterialRun)
def test_process_attachment(): """Test that a process can be attached to a material, and that the connection survives serde""" cake = MaterialRun('Final cake') cake.process = ProcessRun('Icing') cake_data = cake.dump() cake_copy = loads(dumps(cake_data)).as_dict() assert cake_copy['name'] == cake.name assert cake_copy['uids'] == cake.uids assert cake.process.uids['id'] == cake_copy['process'].uids['id'] reconstituted_cake = MaterialRun.build(cake_copy) assert isinstance(reconstituted_cake, MaterialRun) assert isinstance(reconstituted_cake.process, ProcessRun)
def test_register_data_concepts(dataset): """Check that register routes to the correct collections""" expected = { MaterialTemplateCollection: MaterialTemplate("foo"), MaterialSpecCollection: MaterialSpec("foo"), MaterialRunCollection: MaterialRun("foo"), ProcessTemplateCollection: ProcessTemplate("foo"), ProcessSpecCollection: ProcessSpec("foo"), ProcessRunCollection: ProcessRun("foo"), MeasurementTemplateCollection: MeasurementTemplate("foo"), MeasurementSpecCollection: MeasurementSpec("foo"), MeasurementRunCollection: MeasurementRun("foo"), IngredientSpecCollection: IngredientSpec("foo"), IngredientRunCollection: IngredientRun(), PropertyTemplateCollection: PropertyTemplate("bar", bounds=IntegerBounds(0, 1)), ParameterTemplateCollection: ParameterTemplate("bar", bounds=IntegerBounds(0, 1)), ConditionTemplateCollection: ConditionTemplate("bar", bounds=IntegerBounds(0, 1)) } for collection, obj in expected.items(): assert len(obj.uids) == 0 registered = dataset.register(obj) assert len(obj.uids) == 1 assert len(registered.uids) == 1 assert basename(dataset.session.calls[-1].path) == basename( collection._path_template) for pair in obj.uids.items(): assert pair[1] == registered.uids[pair[0]]
def test_simple_deserialization(valid_data): """Ensure that a deserialized Process Run looks sane.""" process_run: ProcessRun = ProcessRun.build(valid_data) assert process_run.uids == {'id': valid_data['uids']['id'], 'my_id': 'process1-v1'} assert process_run.tags == ['baking::cakes', 'danger::low'] assert process_run.conditions[0] == Condition(name='oven temp', value=NominalReal(203.0, ''), origin='measured') assert process_run.parameters == [] assert process_run.file_links == [] assert process_run.template is None assert process_run.output_material is None assert process_run.spec == \ ProcessSpec(name="Spec for proc 1", uids={'id': valid_data['spec']['uids']['id']}, conditions=[Condition(name='oven temp', value=UniformReal(175, 225, ''), origin='specified')] ) assert process_run.name == 'Process 1' assert process_run.notes == 'make sure to use oven mitts' assert process_run.typ == 'process_run'
def test_register_all_data_concepts(dataset): """Check that register_all registers everything and routes to all collections""" bounds = IntegerBounds(0, 1) property_template = PropertyTemplate("bar", bounds=bounds) parameter_template = ParameterTemplate("bar", bounds=bounds) condition_template = ConditionTemplate("bar", bounds=bounds) foo_process_template = ProcessTemplate( "foo", conditions=[[condition_template, bounds]], parameters=[[parameter_template, bounds]]) foo_process_spec = ProcessSpec("foo", template=foo_process_template) foo_process_run = ProcessRun("foo", spec=foo_process_spec) foo_material_template = MaterialTemplate( "foo", properties=[[property_template, bounds]]) foo_material_spec = MaterialSpec("foo", template=foo_material_template, process=foo_process_spec) foo_material_run = MaterialRun("foo", spec=foo_material_spec, process=foo_process_run) baz_template = MaterialTemplate("baz") foo_measurement_template = MeasurementTemplate( "foo", conditions=[[condition_template, bounds]], parameters=[[parameter_template, bounds]], properties=[[property_template, bounds]]) foo_measurement_spec = MeasurementSpec("foo", template=foo_measurement_template) foo_measurement_run = MeasurementRun("foo", spec=foo_measurement_spec, material=foo_material_run) foo_ingredient_spec = IngredientSpec("foo", material=foo_material_spec, process=foo_process_spec) foo_ingredient_run = IngredientRun(spec=foo_ingredient_spec, material=foo_material_run, process=foo_process_run) baz_run = MeasurementRun("baz") # worst order possible expected = { foo_ingredient_run: IngredientRunCollection, foo_ingredient_spec: IngredientSpecCollection, foo_measurement_run: MeasurementRunCollection, foo_measurement_spec: MeasurementSpecCollection, foo_measurement_template: MeasurementTemplateCollection, foo_material_run: MaterialRunCollection, foo_material_spec: MaterialSpecCollection, foo_material_template: MaterialTemplateCollection, foo_process_run: ProcessRunCollection, foo_process_spec: ProcessSpecCollection, foo_process_template: ProcessTemplateCollection, baz_template: MaterialTemplateCollection, baz_run: MeasurementRunCollection, property_template: PropertyTemplateCollection, parameter_template: ParameterTemplateCollection, condition_template: ConditionTemplateCollection } for obj in expected: assert len(obj.uids) == 0 # All should be without ids registered = dataset.register_all(expected.keys()) assert len(registered) == len(expected) seen_ids = set() for obj in expected: assert len(obj.uids) == 1 # All should now have exactly 1 id for pair in obj.uids.items(): assert pair not in seen_ids # All ids are different seen_ids.add(pair) for obj in registered: for pair in obj.uids.items(): assert pair in seen_ids # registered items have the same ids call_basenames = [ call.path.split('/')[-2] for call in dataset.session.calls ] collection_basenames = [ basename(collection._path_template) for collection in expected.values() ] assert set(call_basenames) == set(collection_basenames) assert len(set(call_basenames)) == len( call_basenames) # calls are batched internally # spot check order. Does not check every constraint assert call_basenames.index( basename( IngredientRunCollection._path_template)) > call_basenames.index( basename(IngredientSpecCollection._path_template)) assert call_basenames.index(basename( MaterialRunCollection._path_template)) > call_basenames.index( basename(MaterialSpecCollection._path_template)) assert call_basenames.index( basename( MeasurementRunCollection._path_template)) > call_basenames.index( basename(MeasurementSpecCollection._path_template)) assert call_basenames.index(basename( ProcessRunCollection._path_template)) > call_basenames.index( basename(ProcessSpecCollection._path_template)) assert call_basenames.index(basename( MaterialSpecCollection._path_template)) > call_basenames.index( basename(MaterialTemplateCollection._path_template)) assert call_basenames.index( basename( MeasurementSpecCollection._path_template)) > call_basenames.index( basename(MeasurementTemplateCollection._path_template)) assert call_basenames.index(basename( ProcessSpecCollection._path_template)) > call_basenames.index( basename(ProcessTemplateCollection._path_template)) assert call_basenames.index(basename( MaterialSpecCollection._path_template)) > call_basenames.index( basename(ProcessSpecCollection._path_template)) assert call_basenames.index(basename( MaterialSpecCollection._path_template)) > call_basenames.index( basename(MeasurementSpecCollection._path_template)) assert call_basenames.index( basename(MeasurementTemplateCollection._path_template) ) > call_basenames.index( basename(ConditionTemplateCollection._path_template)) assert call_basenames.index( basename(MeasurementTemplateCollection._path_template) ) > call_basenames.index( basename(ParameterTemplateCollection._path_template)) assert call_basenames.index( basename( MaterialTemplateCollection._path_template)) > call_basenames.index( basename(PropertyTemplateCollection._path_template))
def test_serialization(valid_data): """Ensure that a serialized Process Run looks sane.""" process_run: ProcessRun = ProcessRun.build(valid_data) serialized = process_run.dump() assert serialized == valid_data
def test_soft_process_material_attachment(): """Test that soft attachments are formed from process to output material""" baking = ProcessRun("Bake a cake") cake = MaterialRun("A cake", process=baking) assert baking.output_material == cake