def __init__(self,
              name: str,
              uids: Optional[Dict[str, str]] = None,
              tags: Optional[List[str]] = None,
              notes: Optional[str] = None,
              material: Optional[TaurusMaterialSpec] = None,
              process: Optional[TaurusProcessSpec] = 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):
     DataConcepts.__init__(self, TaurusIngredientSpec.typ)
     TaurusIngredientSpec.__init__(self,
                                   uids=set_default_uid(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)
Beispiel #2
0
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)
Beispiel #3
0
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
Beispiel #4
0
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
Beispiel #5
0
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"
Beispiel #6
0
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)
Beispiel #7
0
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
Beispiel #8
0
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}
Beispiel #9
0
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")
Beispiel #10
0
def make_cake_spec():
    """Define a recipe for making a cake."""
    ###############################################################################################
    # Templates
    tmpl = make_cake_templates()

    ###############################################################################################
    # Objects
    cake = MaterialSpec(
        name="Abstract Cake",
        template=tmpl["Dessert"],
        process=ProcessSpec(
            name='Icing, in General',
            template=tmpl["Icing"],
            tags=[
                'spreading'
            ],
            notes='The act of covering a baked output with frosting'
        ),
        file_links=FileLink(
            filename="Becky's Butter Cake",
            url='https://www.landolakes.com/recipe/16730/becky-s-butter-cake/'
        ),
        tags=[
            'cake::butter cake',
            'dessert::baked::cake',
            'iced::chocolate'
        ],
        notes='Butter cake recipe reminiscent of the 1-2-3-4 cake that Grandma may have baked.'
    )

    ########################
    frosting = MaterialSpec(
        name="Abstract Frosting",
        template=tmpl["Dessert"],
        process=ProcessSpec(
            name='Mixing Frosting, in General',
            template=tmpl["Mixing"],
            tags=[
                'mixing'
            ],
            notes='Combining ingredients to make a sweet frosting'
        ),
        tags=[
            'frosting::chocolate',
            'topping::chocolate'
        ],
        notes='Chocolate frosting'
    )
    IngredientSpec(
        name="{} input".format(frosting.name),
        tags=list(frosting.tags),
        notes='Seems like a lot of frosting',
        labels=['coating'],
        process=cake.process,
        material=frosting,
        absolute_quantity=NominalReal(nominal=0.751, units='kg')
    )

    baked_cake = MaterialSpec(
        name="Abstract Baked Cake",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Baking, in General',
            template=tmpl["Baking in an oven"],
            tags=[
                'oven::baking'
            ],
            notes='Using heat to convert batter into a solid matrix'
        ),
        tags=[
        ],
        notes='The cakey part of the cake'
    )
    IngredientSpec(
        name="{} input".format(baked_cake.name),
        tags=list(baked_cake.tags),
        labels=['substrate'],
        process=cake.process,
        material=baked_cake
    )

    ########################
    batter = MaterialSpec(
        name="Abstract Batter",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Mixing Batter, in General',
            template=tmpl["Mixing"],
            tags=[
                'mixing'
            ],
            notes='Combining ingredients to make a baking feedstock'
        ),
        tags=[
        ],
        notes='The fluid that converts to cake with heat'
    )
    IngredientSpec(
        name="{} input".format(batter.name),
        tags=list(batter.tags),
        labels=['precursor'],
        process=baked_cake.process,
        material=batter
    )

    ########################
    wetmix = MaterialSpec(
        name="Abstract Wet Mix",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Mixing Wet, in General',
            template=tmpl["Mixing"],
            tags=[
                'mixing'
            ],
            notes='Combining wet ingredients to make a baking feedstock'
        ),
        tags=[
        ],
        notes='The wet fraction of a batter'
    )
    IngredientSpec(
        name="{} input".format(wetmix.name),
        tags=list(wetmix.tags),
        labels=['wet'],
        process=batter.process,
        material=wetmix
    )

    drymix = MaterialSpec(
        name="Abstract Dry Mix",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Mixing Dry, in General',
            template=tmpl["Mixing"],
            tags=[
                'mixing'
            ],
            notes='Combining dry ingredients to make a baking feedstock'
        ),
        tags=[
        ],
        notes='The dry fraction of a batter'
    )
    IngredientSpec(
        name="{} input".format(drymix.name),
        tags=list(drymix.tags),
        labels=['dry'],
        process=batter.process,
        material=drymix,
        absolute_quantity=NominalReal(nominal=3.052, units='cups')
    )

    ########################
    flour = MaterialSpec(
        name="Abstract Flour",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Buying Flour, in General',
            template=tmpl["Procurement"],
            tags=[
                'purchase::dry-goods'
            ],
            notes='Purchasing all purpose flour'
        ),
        tags=[
        ],
        notes='All-purpose flour'
    )
    IngredientSpec(
        name="{} input".format(flour.name),
        tags=list(flour.tags),
        labels=['dry'],
        process=drymix.process,
        material=flour,
        volume_fraction=NominalReal(nominal=0.9829, units='')  # 3 cups
    )

    baking_powder = MaterialSpec(
        name="Abstract Baking Powder",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Buying Baking Powder, in General',
            template=tmpl["Procurement"],
            tags=[
                'purchase::dry-goods'
            ],
            notes='Purchasing baking powder'
        ),
        tags=[
        ],
        notes='Leavening agent for cake'
    )
    IngredientSpec(
        name="{} input".format(baking_powder.name),
        tags=list(baking_powder.tags),
        labels=['leavening', 'dry'],
        process=drymix.process,
        material=baking_powder,
        volume_fraction=NominalReal(nominal=0.0137, units='')  # 2 teaspoons
    )

    salt = MaterialSpec(
        name="Abstract Salt",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Buying Salt, in General',
            template=tmpl["Procurement"],
            tags=[
                'purchase::dry-goods'
            ],
            notes='Purchasing salt'
        ),
        tags=[
        ],
        notes='Plain old NaCl'
    )
    IngredientSpec(
        name="{} input".format(salt.name),
        tags=list(salt.tags),
        labels=['dry', 'seasoning'],
        process=drymix.process,
        material=salt,
        volume_fraction=NominalReal(nominal=0.0034, units='')  # 1/2 teaspoon
    )

    sugar = MaterialSpec(
        name="Abstract Sugar",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Buying Sugar, in General',
            template=tmpl["Procurement"],
            tags=[
                'purchase::dry-goods'
            ],
            notes='Purchasing all purpose flour'
        ),
        tags=[
        ],
        notes='Sugar'
    )
    IngredientSpec(
        name="{} input".format(sugar.name),
        tags=list(sugar.tags),
        labels=['wet', 'sweetener'],
        process=wetmix.process,
        material=sugar,
        absolute_quantity=NominalReal(nominal=2, units='cups')
    )

    butter = MaterialSpec(
        name="Abstract Butter",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Buying Butter, in General',
            template=tmpl["Procurement"],
            tags=[
                'purchase::produce'
            ],
            notes='Purchasing butter'
        ),
        tags=[
        ],
        notes='Shortening for making rich, buttery baked goods'
    )
    IngredientSpec(
        name="{} input".format(butter.name),
        tags=list(butter.tags),
        labels=['wet', 'shortening'],
        process=wetmix.process,
        material=butter,
        absolute_quantity=NominalReal(nominal=1, units='cups')
    )
    IngredientSpec(
        name="{} input".format(butter.name),
        tags=list(butter.tags),
        labels=['shortening'],
        process=frosting.process,
        material=butter,
        mass_fraction=NominalReal(nominal=0.1434, units='')  # 1/2 c @ 0.911 g/cc
    )

    eggs = MaterialSpec(
        name="Abstract Eggs",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Buying Eggs, in General',
            template=tmpl["Procurement"],
            tags=[
                'purchase::produce'
            ],
            notes='Purchasing eggs'
        ),
        tags=[
        ],
        notes=''
    )
    IngredientSpec(
        name="{} input".format(eggs.name),
        tags=list(eggs.tags),
        labels=['wet'],
        process=wetmix.process,
        material=eggs,
        absolute_quantity=NominalReal(nominal=4, units='')
    )

    vanilla = MaterialSpec(
        name="Abstract Vanilla",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Buying Vanilla, in General',
            template=tmpl["Procurement"],
            tags=[
                'purchase::dry-goods'
            ],
            notes='Purchasing vanilla'
        ),
        tags=[
        ],
        notes=''
    )
    IngredientSpec(
        name="{} input".format(vanilla.name),
        tags=list(vanilla.tags),
        labels=['wet', 'flavoring'],
        process=wetmix.process,
        material=vanilla,
        absolute_quantity=NominalReal(nominal=2, units='teaspoons')
    )
    IngredientSpec(
        name="{} input".format(vanilla.name),
        tags=list(vanilla.tags),
        labels=['flavoring'],
        process=frosting.process,
        material=vanilla,
        mass_fraction=NominalReal(nominal=0.0231, units='')  # 2 tsp @ 0.879 g/cc
    )

    milk = MaterialSpec(
        name="Abstract Milk",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Buying Milk, in General',
            template=tmpl["Procurement"],
            tags=[
                'purchase::produce'
            ],
            notes='Purchasing milk'
        ),
        tags=[
        ],
        notes=''
    )
    IngredientSpec(
        name="{} input".format(milk.name),
        tags=list(milk.tags),
        labels=['wet'],
        process=batter.process,
        material=milk,
        absolute_quantity=NominalReal(nominal=1, units='cup')
    )
    IngredientSpec(
        name="{} input".format(milk.name),
        tags=list(milk.tags),
        labels=[],
        process=frosting.process,
        material=milk,
        mass_fraction=NominalReal(nominal=0.0816, units='')  # 1/4 c @ 1.037 g/cc
    )

    chocolate = MaterialSpec(
        name="Abstract Chocolate",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Buying Chocolate, in General',
            template=tmpl["Procurement"],
            tags=[
                'purchase::dry-goods'
            ],
            notes='Purchasing chocolate'
        ),
        tags=[
        ],
        notes=''
    )
    IngredientSpec(
        name="{} input".format(chocolate.name),
        tags=list(chocolate.tags),
        labels=['flavoring'],
        process=frosting.process,
        material=chocolate,
        mass_fraction=NominalReal(nominal=0.1132, units='')  # 3 oz.
    )

    powder_sugar = MaterialSpec(
        name="Abstract Powdered Sugar",
        template=tmpl["Generic Material"],
        process=ProcessSpec(
            name='Buying Powdered Sugar, in General',
            template=tmpl["Procurement"],
            tags=[
                'purchase::dry-goods'
            ],
            notes='Purchasing powdered sugar'
        ),
        tags=[
        ],
        notes='Granulated sugar mixed with corn starch'
    )
    IngredientSpec(
        name="{} input".format(powder_sugar.name),
        tags=list(powder_sugar.tags),
        labels=['flavoring'],
        process=frosting.process,
        material=powder_sugar,
        mass_fraction=NominalReal(nominal=0.6387, units='')  # 4 c @ 30 g/ 0.25 cups
    )
    return cake