def __init__(self, name: str, *, uids: Optional[Dict[str, str]] = None, tags: Optional[List[str]] = None, notes: Optional[str] = None, material: Optional[GEMDMaterialSpec] = None, process: Optional[GEMDProcessSpec] = None, mass_fraction: Optional[ContinuousValue] = None, volume_fraction: Optional[ContinuousValue] = None, number_fraction: Optional[ContinuousValue] = None, absolute_quantity: Optional[ContinuousValue] = None, labels: Optional[List[str]] = None, file_links: Optional[List[FileLink]] = None): if uids is None: uids = dict() DataConcepts.__init__(self, GEMDIngredientSpec.typ) GEMDIngredientSpec.__init__(self, uids=uids, tags=tags, notes=notes, material=material, process=process, mass_fraction=mass_fraction, volume_fraction=volume_fraction, number_fraction=number_fraction, absolute_quantity=absolute_quantity, labels=labels, name=name, file_links=file_links)
def test_invalid_assignment(): """Invalid assignments to `process` or `material` throw a TypeError.""" with pytest.raises(TypeError): IngredientSpec(name="name", material=NominalReal(3, '')) with pytest.raises(TypeError): IngredientSpec(name="name", process="process") with pytest.raises(TypeError): IngredientSpec() # Name is required
def test_bad_has_template(): """Make sure the non-implementation of HasTemplate behaves properly.""" assert isinstance(None, IngredientSpec(name="name")._template_type()), \ "Ingredients didn't have NoneType templates" assert IngredientSpec(name="name").template is None, \ "An ingredient didn't have a null template." with pytest.raises( AttributeError): # Note an AttributeError, not a TypeError IngredientSpec(name="name").template = 1
def test_invalid_quantities(invalid_quantity): """Check that any non-continuous value for a quantity throws a TypeError.""" with pytest.raises(TypeError): IngredientSpec(name="name", mass_fraction=invalid_quantity) with pytest.raises(TypeError): IngredientSpec(name="name", volume_fraction=invalid_quantity) with pytest.raises(TypeError): IngredientSpec(name="name", number_fraction=invalid_quantity) with pytest.raises(TypeError): IngredientSpec(name="name", absolute_quantity=invalid_quantity)
def test_valid_quantities(valid_quantity): """ Check that all quantities must be continuous values. There are no restrictions on the value or the units. Although a volume fraction of -5 kg does not make physical sense, it will not throw an error. """ ingred = IngredientSpec(name="name", mass_fraction=valid_quantity) assert ingred.mass_fraction == valid_quantity ingred = IngredientSpec(name="name", volume_fraction=valid_quantity) assert ingred.volume_fraction == valid_quantity ingred = IngredientSpec(name="name", number_fraction=valid_quantity) assert ingred.number_fraction == valid_quantity ingred = IngredientSpec(name="name", absolute_quantity=valid_quantity) assert ingred.absolute_quantity == valid_quantity
def test_scope_control(): """Serializing a nested object should be identical to individually serializing each piece.""" input_material = MaterialSpec() process = ProcessSpec() IngredientSpec(material=input_material, process=process) material = MaterialSpec(process=process) # Verify the default scope is there default_json = GEMDJson() default_text = default_json.dumps(material) assert "auto" in default_text assert "custom" not in default_text # Clear out ids input_material.uids = {} process.uids = {} process.ingredients[0].uids = {} input_material.uids = {} material.uids = {} # Verify the default scope is there custom_json = GEMDJson(scope='custom') custom_text = custom_json.dumps(material) assert "auto" not in custom_text assert "custom" in custom_text
def test_circular_crawl(): """Test that make_instance can handle a circular set of linked objects.""" proc = ProcessSpec("process name") mat = MaterialSpec("material name", process=proc) IngredientSpec(name="ingredient name", material=mat, process=proc) mat_run = make_instance(mat) assert mat_run == mat_run.process.ingredients[0].material
def test_valid_quantities(valid_quantity, caplog): """ Check that all quantities must be continuous values. There are no restrictions on the value or the units. Although a volume fraction of -5 kg does not make physical sense, it will not throw an error. """ with validation_level(WarningLevel.IGNORE): ingred = IngredientSpec(name="name", mass_fraction=valid_quantity) assert ingred.mass_fraction == valid_quantity ingred = IngredientSpec(name="name", volume_fraction=valid_quantity) assert ingred.volume_fraction == valid_quantity ingred = IngredientSpec(name="name", number_fraction=valid_quantity) assert ingred.number_fraction == valid_quantity ingred = IngredientSpec(name="name", absolute_quantity=valid_quantity) assert ingred.absolute_quantity == valid_quantity assert len(caplog.records) == 0, "Warned when validation set to IGNORE."
def test_ingredient_spec(): """Tests that a process can house an ingredient, and that pairing survives serialization.""" # Create a ProcessSpec proc_spec = ProcessSpec(name="a process spec", tags=["tag1", "tag2"]) IngredientSpec(name='Input', material=MaterialSpec(name='Raw'), process=proc_spec) # Make copies of both specs proc_spec_copy = loads(dumps(proc_spec)) assert proc_spec_copy == proc_spec, "Full structure wasn't preserved across serialization"
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_make_instance(): """Build up several linked objects and test their properties.""" msr_spec = MeasurementSpec() assert isinstance(make_instance(msr_spec), MeasurementRun) mat_spec = MaterialSpec(name='Mat name') mat_spec.process = ProcessSpec(name='Pro name') IngredientSpec(name='Ing label', process=mat_spec.process) mat_spec.process.ingredients[0].material = MaterialSpec(name='Baby mat name') mat_run = make_instance(mat_spec) assert isinstance(mat_run, MaterialRun) assert isinstance(mat_run.process, ProcessRun) assert isinstance(mat_run.process.ingredients[0], IngredientRun) assert isinstance(mat_run.process.ingredients[0].material, MaterialRun) assert mat_run.process.spec == mat_run.spec.process ingredient = mat_run.process.ingredients[0] assert ingredient.spec == mat_run.spec.process.ingredients[0] assert ingredient.material.spec == mat_run.spec.process.ingredients[0].material
def test_validation_control(caplog): """Verify that when validation is requested, limits are enforced.""" with validation_level(WarningLevel.WARNING): IngredientSpec(name="name", mass_fraction=NominalReal(0.5, '')) assert len(caplog.records) == 0, "Warned on valid values with WARNING." IngredientSpec(name="name", mass_fraction=NominalReal(5, '')) assert len( caplog.records) == 1, "Didn't warn on invalid values with WARNING." IngredientSpec(name="name", mass_fraction=NominalReal(0.5, 'm')) assert len( caplog.records) == 2, "Didn't warn on invalid units with WARNING." with validation_level(WarningLevel.FATAL): # The following should not raise an exception IngredientSpec(name="name", mass_fraction=NominalReal(0.5, '')) with pytest.raises(ValueError): IngredientSpec(name="name", mass_fraction=NominalReal(5, '')) with pytest.raises(ValueError): IngredientSpec(name="name", mass_fraction=NominalReal(0.5, 'm'))
def test_ingredient_reassignment(): """Check that an ingredient spec can be re-assigned to a new process spec.""" boiling = ProcessSpec("Boil potatoes") frying = ProcessSpec("Fry potatoes") oil = IngredientSpec(name="Oil", process=boiling) potatoes = IngredientSpec(name="Potatoes", 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}