def test_object_key_substitution(): """Test that client can copy a dictionary in which keys are BaseEntity objects.""" spec = ProcessSpec("A process spec", uids={ 'id': str(uuid4()), 'auto': str(uuid4()) }) run1 = ProcessRun("A process run", spec=spec, uids={ 'id': str(uuid4()), 'auto': str(uuid4()) }) run2 = ProcessRun("Another process run", spec=spec, uids={'id': str(uuid4())}) process_dict = {spec: [run1, run2]} subbed = substitute_links(process_dict, native_uid='auto') for key, value in subbed.items(): assert key == LinkByUID.from_entity(spec, name='auto') assert LinkByUID.from_entity(run1, name='auto') in value assert LinkByUID.from_entity(run2) in value reverse_process_dict = {run2: spec} subbed = substitute_links(reverse_process_dict, native_uid='auto') for key, value in subbed.items(): assert key == LinkByUID.from_entity(run2) assert value == LinkByUID.from_entity(spec, name='auto')
def test_flatten_empty_history(): """Test that flatten works when the objects are empty and go through a whole history.""" procured = ProcessSpec(name="procured") input = MaterialSpec(name="foo", process=procured) transform = ProcessSpec(name="transformed") ingredient = IngredientSpec(name="input", material=input, process=transform) procured_run = ProcessRun(name="procured", spec=procured) input_run = MaterialRun(name="foo", process=procured_run, spec=input) transform_run = ProcessRun(name="transformed", spec=transform) ingredient_run = IngredientRun(material=input_run, process=transform_run, spec=ingredient) assert len(flatten(procured)) == 1 assert len(flatten(input)) == 1 assert len(flatten(ingredient)) == 3 assert len(flatten(transform)) == 3 assert len(flatten(procured_run)) == 3 assert len(flatten(input_run)) == 3 assert len(flatten(ingredient_run)) == 7 assert len(flatten(transform_run)) == 7
def test_process_reassignment(): """Test that a material can be assigned to a new process.""" drying = ProcessRun("drying") welding = ProcessRun("welding") powder = MaterialRun("Powder", process=welding) assert powder.process == welding assert welding.output_material == powder powder.process = drying assert powder.process == drying assert drying.output_material == powder assert welding.output_material is None
def test_order_objects(): """Test that sorting works when given objects.""" unsorted = [MaterialRun("bar"), ProcessRun("foo")] sorted_list = sorted(unsorted, key=lambda x: writable_sort_order(x)) assert isinstance(sorted_list[0], ProcessRun) assert isinstance(sorted_list[1], MaterialRun)
def test_dict_serialization(): """Test that a dictionary can be serialized and then deserialized as a taurus object.""" process = ProcessRun("A process") mat = MaterialRun("A material", process=process) meas = MeasurementRun("A measurement", material=mat) copy = loads(dumps(meas.as_dict())) assert copy == meas
def test_unexpected_serialization(): """Trying to serialize an unexpected class should throw a TypeError.""" class DummyClass: def __init__(self, foo): self.foo = foo with pytest.raises(TypeError): dumps(ProcessRun("A process", notes=DummyClass("something")))
def test_tuple_sub(): """substitute_objects() should correctly substitute tuple values.""" proc = ProcessRun('foo', uids={'id': '123'}) proc_link = LinkByUID.from_entity(proc) index = {(proc_link.scope, proc_link.id): proc} tup = (proc_link,) subbed = substitute_objects(tup, index) assert subbed[0] == proc
def test_invalid_assignment(): """Invalid assignments to `process` or `spec` throw a TypeError.""" with pytest.raises(TypeError): MaterialRun(name=12) with pytest.raises(TypeError): MaterialRun("name", spec=ProcessRun("a process")) with pytest.raises(TypeError): MaterialRun("name", process=MaterialSpec("a spec"))
def test_flatmap_unidirectional_ordering(): """Test that the unidirecitonal setting is obeyed.""" # The writeable link is ingredient -> process, not process -> ingredients proc = ProcessRun(name="foo") IngredientRun(notes="bar", process=proc) assert len(recursive_flatmap(proc, lambda x: [x], unidirectional=False)) == 2 assert len(recursive_flatmap(proc, lambda x: [x], unidirectional=True)) == 0
def test_unexpected_deserialization(): """Trying to deserialize an unexpected class should throw a TypeError.""" class DummyClass(DictSerializable): typ = 'dummy_class' def __init__(self, foo): self.foo = foo # DummyClass cannot be serialized since dumps will round-robin serialize # in the substitute_links method with pytest.raises(TypeError): dumps(ProcessRun("A process", notes=DummyClass("something")))
def test_unexpected_deserialization(): """Trying to deserialize an unexpected class should throw a TypeError.""" class DummyClass(DictSerializable): typ = 'dummy_class' def __init__(self, foo): self.foo = foo # DummyClass can be serialized because it is a DictSerializable, but cannot be # deserialized because it is not in the _clazzes list. serialized = dumps(ProcessRun("A process", notes=DummyClass("something"))) with pytest.raises(TypeError): loads(serialized)
def test_dictionary_substitution(): """substitute_objects() should substitute LinkByUIDs that occur in dict keys and values.""" proc = ProcessRun("A process", uids={'id': '123'}) mat = MaterialRun("A material", uids={'generic id': '38f8jf'}) proc_link = LinkByUID.from_entity(proc) mat_link = LinkByUID.from_entity(mat) index = {(mat_link.scope.lower(), mat_link.id): mat, (proc_link.scope.lower(), proc_link.id): proc} test_dict = {LinkByUID.from_entity(proc): LinkByUID.from_entity(mat)} substitute_objects(test_dict, index) assert test_dict[proc] == mat
def test_many_ingredients(): """Test that ingredients remain connected to processes when round-robined through json.""" proc = ProcessRun("foo", spec=ProcessSpec("sfoo")) expected = [] for i in range(10): mat = MaterialRun(name=str(i), spec=MaterialSpec("s{}".format(i))) i_spec = IngredientSpec(name="i{}".format(i), material=mat.spec, process=proc.spec) IngredientRun(process=proc, material=mat, spec=i_spec) expected.append("i{}".format(i)) reloaded = loads(dumps(proc)) assert len(list(reloaded.ingredients)) == 10 names = [x.name for x in reloaded.ingredients] assert sorted(names) == sorted(expected)
def test_process_run(): """Test that a process run can house a material, and that it survives serde.""" process_run = ProcessRun("Bake a cake", uids={'My_ID': 17}) material_run = MaterialRun("A cake", process=process_run) # Check that a bi-directional link is established assert material_run.process == process_run assert process_run.output_material == material_run copy_material = loads(dumps(material_run)) assert dumps(copy_material) == dumps(material_run) assert 'output_material' in repr(process_run) assert 'process' in repr(material_run)
def test_recursive_foreach(): """Test that recursive foreach will actually walk through a material history.""" mat_run = MaterialRun("foo") process_run = ProcessRun("bar") IngredientRun(process=process_run, material=mat_run) output = MaterialRun(process=process_run) # property templates are trickier than templates because they are referenced in attributes template = PropertyTemplate("prop", bounds=RealBounds(0, 1, "")) prop = Property("prop", value=NominalReal(1.0, ""), template=template) MeasurementRun("check", material=output, properties=prop) types = [] recursive_foreach(output, lambda x: types.append(x.typ)) expected = [ "ingredient_run", "material_run", "material_run", "process_run", "measurement_run", "property_template" ] assert sorted(types) == sorted(expected)
def test_serialize(): """Serializing a nested object should be identical to individually serializing each piece.""" condition = Condition(name="A condition", value=NominalReal(7, '')) parameter = Parameter(name="A parameter", value=NormalReal(mean=17, std=1, units='')) input_material = MaterialRun(tags="input") process = ProcessRun(tags="A tag on a process run") ingredient = IngredientRun(material=input_material, process=process) material = MaterialRun(tags=["A tag on a material"], process=process) measurement = MeasurementRun(tags="A tag on a measurement", conditions=condition, parameters=parameter, material=material) # serialize the root of the tree native_object = json.loads(dumps(measurement)) # ingredients don't get serialized on the process assert(len(native_object[0]) == 3) assert(native_object[1]["type"] == LinkByUID.typ) # serialize all of the nodes native_batch = json.loads(dumps([material, process, measurement, ingredient])) assert(len(native_batch[0]) == 5) assert(len(native_batch[1]) == 4) assert(all(x["type"] == LinkByUID.typ for x in native_batch[1]))
def make_data_island(density, bulk_modulus, firing_temperature, binders, powders, tag=None): """Helper function to create a relatively involved data island.""" binder_specs = keymap(lambda x: MaterialSpec(name=x), binders) powder_specs = keymap(lambda x: MaterialSpec(name=x), powders) binder_runs = keymap(lambda x: MaterialRun(spec=x), binder_specs) powder_runs = keymap(lambda x: MaterialRun(spec=x), powder_specs) all_input_materials = keymap(lambda x: x.spec.name, merge(binder_runs, powder_runs)) mixing_composition = Condition( name="composition", value=NominalComposition(all_input_materials) ) mixing_process = ProcessRun( tags=["mixing"], conditions=[mixing_composition] ) binder_ingredients = [] for run in binder_runs: binder_ingredients.append( IngredientRun( material=run, process=mixing_process, mass_fraction=NominalReal(binders[run.spec.name], ''), ) ) powder_ingredients = [] for run in powder_runs: powder_ingredients.append( IngredientRun( material=run, process=mixing_process, mass_fraction=NominalReal(powders[run.spec.name], ''), ) ) green_sample = MaterialRun(process=mixing_process) measured_firing_temperature = Condition( name="Firing Temperature", value=UniformReal(firing_temperature - 0.5, firing_temperature + 0.5, 'degC'), template=firing_temperature_template ) specified_firing_setting = Parameter( name="Firing setting", value=DiscreteCategorical("hot") ) firing_spec = ProcessSpec(template=firing_template) firing_process = ProcessRun( conditions=[measured_firing_temperature], parameters=[specified_firing_setting], spec=firing_spec ) IngredientRun( green_sample, process=firing_process, mass_fraction=NormalReal(1.0, 0.0, ''), volume_fraction=NormalReal(1.0, 0.0, ''), number_fraction=NormalReal(1.0, 0.0, '') ) measured_density = Property( name="Density", value=NominalReal(density, ''), template=density_template ) measured_modulus = Property( name="Bulk modulus", value=NormalReal(bulk_modulus, bulk_modulus / 100.0, '') ) measurement_spec = MeasurementSpec(template=measurement_template) measurement = MeasurementRun( properties=[measured_density, measured_modulus], spec=measurement_spec ) tags = [tag] if tag else [] material_spec = MaterialSpec(template=material_template) material_run = MaterialRun(process=firing_process, tags=tags, spec=material_spec) measurement.material = material_run return material_run