def dumps(self, obj, **kwargs): """ Serialize a gemd object, or container of them, into a json-formatting string. Parameters ---------- obj: DictSerializable or List[DictSerializable] The object(s) to serialize to a string. **kwargs: keyword args, optional Optional keyword arguments to pass to `json.dumps()`. Returns ------- str A string version of the serialized objects. """ # create a top level list of [flattened_objects, link-i-fied return value] res = {"object": obj} additional = flatten(res) res = substitute_links(res) res["context"] = additional return json_builtin.dumps(res, cls=GEMDEncoder, sort_keys=True, **kwargs)
def test_complex_substitutions(): """Make sure accounting works for realistic objects.""" root = MaterialRun("root", process=ProcessRun("root", spec=ProcessSpec("root")), spec=MaterialSpec("root")) root.spec.process = root.process.spec input = MaterialRun("input", process=ProcessRun("input", spec=ProcessSpec("input")), spec=MaterialSpec("input")) input.spec.process = input.process.spec IngredientRun(process=root.process, material=input, spec=IngredientSpec("ingredient", process=root.process.spec, material=input.spec)) param = ParameterTemplate("Param", bounds=RealBounds(-1, 1, "m")) root.process.spec.template = ProcessTemplate("Proc", parameters=[param]) root.process.parameters.append( Parameter("Param", value=NormalReal(0, 1, 'm'), template=param)) links = flatten(root, scope="test-scope") index = make_index(links) rebuild = substitute_objects(links, index, inplace=True) rebuilt_root = next(x for x in rebuild if x.name == root.name and x.typ == root.typ) all_objs = recursive_flatmap(rebuilt_root, func=lambda x: [x], unidirectional=False) unique = [x for i, x in enumerate(all_objs) if i == all_objs.index(x)] assert not any(isinstance(x, LinkByUID) for x in unique), "All are objects" assert len(links) == len(unique), "Objects are missing"
def test_flatten_bounds(): """Test that flatten works when the objects contain other objects.""" bounds = CategoricalBounds(categories=["foo", "bar"]) template = ProcessTemplate( "spam", conditions=[(ConditionTemplate(name="eggs", bounds=bounds), bounds)] ) spec = ProcessSpec(name="spec", template=template) flat = flatten(spec, 'test-scope') assert len(flat) == 2, "Expected 2 flattened objects"
def test_flatten(): """Test that gemd utility methods can be applied to citrine-python objects. Citrine-python resources extend the gemd data model, so the gemd operations should work on them. """ bounds = CategoricalBounds(categories=["foo", "bar"]) template = ProcessTemplate( "spam", conditions=[(ConditionTemplate(name="eggs", bounds=bounds), bounds)] ) spec = ProcessSpec(name="spec", template=template) flat = flatten(spec, scope='testing') assert len(flat) == 3, "Expected 3 flattened objects"
def test_equality(): """Test that equality check works as expected.""" spec = ProcessSpec("A spec", tags=["a tag"]) run1 = ProcessRun("A process", spec=spec) run2 = deepcopy(run1) assert run1 == run2, "Copy somehow failed" IngredientRun(process=run2) assert run1 != run2 run3 = deepcopy(run2) assert run3 == run2, "Copy somehow failed" run3.ingredients[0].tags.append('A tag') assert run3 != run2 run4 = next(x for x in flatten(run3, 'test-scope') if isinstance(x, ProcessRun)) assert run4 == run3, "Flattening removes measurement references, but that's okay"
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_equality(): """Test that equality check works as expected.""" spec1 = ProcessSpec("A spec") spec2 = ProcessSpec("A spec", tags=["a tag"]) assert spec1 != spec2 spec3 = deepcopy(spec1) assert spec1 == spec3, "Copy somehow failed" IngredientSpec("An ingredient", process=spec3) assert spec1 != spec3 spec4 = deepcopy(spec3) assert spec4 == spec3, "Copy somehow failed" spec4.ingredients[0].tags.append('A tag') assert spec4 != spec3 spec5 = next(x for x in flatten(spec4, 'test-scope') if isinstance(x, ProcessSpec)) assert spec5 == spec4, "Flattening removes measurement references, but that's okay"
def test_default_scope(): """Test flatten exceptions around providing a scope.""" ps_one = ProcessSpec(name="one") with pytest.raises(ValueError): flatten(ps_one) pr_one = ProcessRun(name="one", uids={'my': 'outer'}, spec=ps_one) with pytest.raises(ValueError): flatten(pr_one) ps_one.uids['my'] = 'id' assert len(flatten(pr_one)) == 2 two = ProcessRun(name="two", spec=ProcessSpec(name="two")) assert len(flatten(two, scope="my")) == 2
def test_equality(): """Test that equality check works as expected.""" spec = MaterialSpec("A spec", properties=PropertyAndConditions( property=Property("a property", value=NominalReal(3, ''))), tags=["a tag"]) mat1 = MaterialRun("A material", spec=spec) mat2 = MaterialRun("A material", spec=spec, tags=["A tag"]) assert mat1 == deepcopy(mat1) assert mat1 != mat2 assert mat1 != "A material" mat3 = deepcopy(mat1) assert mat1 == mat3, "Copy somehow failed" MeasurementRun("A measurement", material=mat3) assert mat1 != mat3 mat4 = deepcopy(mat3) assert mat4 == mat3, "Copy somehow failed" mat4.measurements[0].tags.append('A tag') assert mat4 != mat3 mat5 = next(x for x in flatten(mat4, 'test-scope') if isinstance(x, MaterialRun)) assert mat5 == mat4, "Flattening removes measurement references, but that's okay"