def test_serialized_history(): """Test the serialization of a complete material history.""" # Create several runs and specs linked together buy_spec = LinkByUID("id", "pr723") cookie_dough_spec = MaterialSpec("cookie dough spec", process=buy_spec) buy_cookie_dough = ProcessRun("Buy cookie dough", uids={'id': '32283'}, spec=buy_spec) cookie_dough = MaterialRun("cookie dough", process=buy_cookie_dough, spec=cookie_dough_spec) bake = ProcessRun("bake cookie dough", conditions=[ Condition("oven temp", origin='measured', value=NominalReal(357, 'degF'))]) IngredientRun(material=cookie_dough, process=bake, number_fraction=NominalReal(1, '')) cookie = MaterialRun("cookie", process=bake, tags=["chocolate chip", "drop"]) MeasurementRun("taste", material=cookie, properties=[ Property("taste", value=DiscreteCategorical("scrumptious"))]) cookie_history = complete_material_history(cookie) # There are 7 entities in the serialized list: cookie dough (spec & run), buy cookie dough, # cookie dough ingredient, bake cookie dough, cookie, taste assert len(cookie_history) == 7 for entity in cookie_history: assert len(entity['uids']) > 0, "Serializing material history should assign uids." # Check that the measurement points to the material taste_dict = next(x for x in cookie_history if x.get('type') == 'measurement_run') cookie_dict = next(x for x in cookie_history if x.get('name') == 'cookie') scope = taste_dict.get('material').get('scope') assert taste_dict.get('material').get('id') == cookie_dict.get('uids').get(scope) # Check that both the material spec and the process run point to the same process spec. # Because that spec was initially a LinkByUID, this also tests the methods ability to # serialize a LinkByUID. cookie_dough_spec_dict = next(x for x in cookie_history if x.get('type') == 'material_spec') buy_cookie_dough_dict = next(x for x in cookie_history if x.get('name') == 'Buy cookie dough') assert cookie_dough_spec_dict.get('process') == buy_spec.as_dict() assert buy_cookie_dough_dict.get('spec') == buy_spec.as_dict()
def test_template_access(): """A process run's template should be equal to its spec's template.""" template = ProcessTemplate("process template", uids={'id': str(uuid4())}) spec = ProcessSpec("A spec", uids={'id': str(uuid4())}, template=template) proc = ProcessRun("A run", uids={'id': str(uuid4())}, spec=spec) assert proc.template == template proc.spec = LinkByUID.from_entity(spec) assert proc.template is None
def test_link_by_uid(): """Test that linking works.""" root = MaterialRun(name='root', process=ProcessRun(name='root proc')) leaf = MaterialRun(name='leaf', process=ProcessRun(name='leaf proc')) IngredientRun(process=root.process, material=leaf) IngredientRun(process=root.process, material=LinkByUID.from_entity(leaf)) copy = loads(dumps(root)) assert copy.process.ingredients[0].material == copy.process.ingredients[ 1].material
def crawler(spec): from gemd.entity.object.measurement_spec import MeasurementSpec from gemd.entity.object.measurement_run import MeasurementRun from gemd.entity.object.material_spec import MaterialSpec from gemd.entity.object.material_run import MaterialRun from gemd.entity.object.ingredient_spec import IngredientSpec from gemd.entity.object.ingredient_run import IngredientRun from gemd.entity.object.process_spec import ProcessSpec from gemd.entity.object.process_run import ProcessRun if id(spec) in seen: return seen[id(spec)] if isinstance(spec, MeasurementSpec): seen[id(spec)] = MeasurementRun(name=spec.name, spec=spec) elif isinstance(spec, MaterialSpec): seen[id(spec)] = MaterialRun(name=spec.name, spec=spec) seen[id(spec)].process = crawler( spec.process) if spec.process else None elif isinstance(spec, IngredientSpec): seen[id(spec)] = IngredientRun(spec=spec) seen[id(spec)].material = crawler( spec.material) if spec.material else None elif isinstance(spec, ProcessSpec): seen[id(spec)] = ProcessRun(name=spec.name, spec=spec) for x in spec.ingredients: crawler(x).process = seen[id(spec)] else: raise TypeError( 'Passed object is not a spec-like object({})'.format( type(spec))) # Should we assume that the same MaterialSpec in different parts of the tree # yields the same MaterialRun? return seen[id(spec)]
def test_ingredient_reassignment(): """Check that an ingredient run can be re-assigned to a new process run.""" boiling = ProcessRun("Boil potatoes") frying = ProcessRun("Fry potatoes") oil = IngredientRun(process=boiling) potatoes = IngredientRun(process=boiling) assert oil.process == boiling assert set(boiling.ingredients) == {oil, potatoes} assert frying.ingredients == [] oil.process = frying assert oil.process == frying assert boiling.ingredients == [potatoes] assert frying.ingredients == [oil] potatoes.process = frying assert potatoes.process == frying assert boiling.ingredients == [] assert set(frying.ingredients) == {oil, potatoes}
def test_ingredient_run(): """Tests that a process can house an ingredient, and that pairing survives serialization.""" # Create a ProcessSpec proc_run = ProcessRun(name="a process spec", tags=["tag1", "tag2"]) ingred_run = IngredientRun(material=MaterialRun(name='Raw'), process=proc_run) # Make copies of both specs proc_run_copy = loads(dumps(proc_run)) assert proc_run_copy == proc_run, "Full structure wasn't preserved across serialization" assert 'process' in repr(ingred_run) assert 'ingredients' in repr(proc_run)
def test_process_spec(): """Tests that the Process Spec/Run connection persists when serializing.""" # Create the ProcessSpec condition1 = Condition(name="a condition on the process in general") spec = ProcessSpec(conditions=condition1) # Create the ProcessRun with a link to the ProcessSpec from above condition2 = Condition(name="a condition on this process run in particular") process = ProcessRun(conditions=condition2, spec=spec) copy_process = loads(dumps(process)) assert dumps(copy_process.spec) == dumps(spec), \ "Process spec should be preserved through serialization"
def __init__(self, name: str, *, uids: Optional[Dict[str, str]] = None, tags: Optional[List[str]] = None, notes: Optional[str] = None, conditions: Optional[List[Condition]] = None, parameters: Optional[List[Parameter]] = None, spec: Optional[GEMDProcessSpec] = None, file_links: Optional[List[FileLink]] = None, source: Optional[PerformedSource] = None): if uids is None: uids = dict() DataConcepts.__init__(self, GEMDProcessRun.typ) GEMDProcessRun.__init__(self, name=name, uids=uids, tags=tags, conditions=conditions, parameters=parameters, spec=spec, file_links=file_links, notes=notes, source=source)
def test_invalid_assignment(): """Invalid assignments to `spec` throw a TypeError.""" with pytest.raises(TypeError): ProcessRun("name", spec=[ProcessSpec("spec")])
def test_serde(): """Test that an object with a case-insensitive dict can be serialized properly.""" process = ProcessRun("A process", uids={'Foo': str(17)}) process_copy = loads(dumps(process)) assert process == process_copy assert process_copy.uids['foo'] == process_copy.uids['Foo']