def test_errors():
    """Make sure invalid bounds raise value errors."""
    with pytest.raises(ValueError):
        IntegerBounds()

    with pytest.raises(ValueError):
        IntegerBounds(0, float("inf"))

    with pytest.raises(ValueError):
        IntegerBounds(10, 1)
Beispiel #2
0
def test_contains():
    """Test contains logic."""
    int_bounds = IntegerBounds(0, 2)

    assert int_bounds.contains(IntegerBounds(0, 1))
    assert int_bounds.contains(IntegerBounds(1, 2))
    assert not int_bounds.contains(IntegerBounds(1, 3))
    assert not int_bounds.contains(None)
    with pytest.raises(TypeError):
        int_bounds.contains([0, 1])
Beispiel #3
0
def test_filter_by_attribute_bounds(collection, session):
    # Given
    sample_run = MaterialRunDataFactory()
    session.set_response({'contents': [sample_run]})
    link = LinkByUIDFactory()
    bounds = {link: IntegerBounds(1, 5)}

    # When
    runs = collection.filter_by_attribute_bounds(bounds, page=1, per_page=10)

    # Then
    assert 1 == session.num_calls
    expected_call = FakeCall(
        method='POST',
        path='projects/{}/material-runs/filter-by-attribute-bounds'.format(
            collection.project_id),
        params={
            "page": 1,
            "per_page": 10,
            "dataset_id": str(collection.dataset_id)
        },
        json={
            'attribute_bounds': {
                link.id: {
                    'lower_bound': 1,
                    'upper_bound': 5,
                    'type': 'integer_bounds'
                }
            }
        })
    assert expected_call == session.last_call
    assert 1 == len(runs)
    assert sample_run['uids'] == runs[0].uids
def test_type_mismatch():
    """Test that incompatible types cannot be matched against RealBounds."""
    bounds = RealBounds(0, 1, default_units="meters")
    assert not bounds.contains(IntegerBounds(0, 1))
    assert not bounds.contains(None)
    with pytest.raises(TypeError):
        bounds.contains([.33, .66])
def test_object_template_serde():
    """Test serde of an object template."""
    length_template = PropertyTemplate("Length", bounds=RealBounds(2.0, 3.5, 'cm'))
    sub_bounds = RealBounds(2.5, 3.0, 'cm')
    color_template = PropertyTemplate("Color", bounds=CategoricalBounds(["red", "green", "blue"]))
    # Properties are a mixture of property templates and [template, bounds], pairs
    block_template = MaterialTemplate("Block", properties=[[length_template, sub_bounds],
                                                           color_template])
    copy_template = MaterialTemplate.build(block_template.dump())
    assert copy_template == block_template

    # Tests below exercise similar code, but for measurement and process templates
    pressure_template = ConditionTemplate("pressure", bounds=RealBounds(0.1, 0.11, 'MPa'))
    index_template = ParameterTemplate("index", bounds=IntegerBounds(2, 10))
    meas_template = MeasurementTemplate("A measurement of length", properties=[length_template],
                                        conditions=[pressure_template], description="Description",
                                        parameters=[index_template], tags=["foo"])
    assert MeasurementTemplate.build(meas_template.dump()) == meas_template

    proc_template = ProcessTemplate("Make an object", parameters=[index_template],
                                    conditions=[pressure_template], allowed_labels=["Label"],
                                    allowed_names=["first sample", "second sample"])
    assert ProcessTemplate.build(proc_template.dump()) == proc_template

    # Check that serde still works if the template is a LinkByUID
    pressure_template.uids['id'] = '12345'  # uids['id'] not populated by default
    proc_template.conditions[0][0] = LinkByUID('id', pressure_template.uids['id'])
    assert ProcessTemplate.build(proc_template.dump()) == proc_template
def test_object_template_validation():
    """Test that attribute templates are validated against given bounds."""
    length_template = PropertyTemplate("Length", bounds=RealBounds(2.0, 3.5, 'cm'))
    dial_template = ConditionTemplate("dial", bounds=IntegerBounds(0, 5))
    color_template = ParameterTemplate("Color", bounds=CategoricalBounds(["red", "green", "blue"]))

    with pytest.raises(TypeError):
        MaterialTemplate()

    with pytest.raises(ValueError):
        MaterialTemplate("Block", properties=[[length_template, RealBounds(3.0, 4.0, 'cm')]])

    with pytest.raises(ValueError):
        ProcessTemplate("a process", conditions=[[color_template, CategoricalBounds(["zz"])]])
        
    with pytest.raises(ValueError):
        MeasurementTemplate("A measurement", parameters=[[dial_template, IntegerBounds(-3, -1)]])
Beispiel #7
0
def test_register_data_concepts(dataset):
    """Check that register routes to the correct collections"""
    expected = {
        MaterialTemplateCollection:
        MaterialTemplate("foo"),
        MaterialSpecCollection:
        MaterialSpec("foo"),
        MaterialRunCollection:
        MaterialRun("foo"),
        ProcessTemplateCollection:
        ProcessTemplate("foo"),
        ProcessSpecCollection:
        ProcessSpec("foo"),
        ProcessRunCollection:
        ProcessRun("foo"),
        MeasurementTemplateCollection:
        MeasurementTemplate("foo"),
        MeasurementSpecCollection:
        MeasurementSpec("foo"),
        MeasurementRunCollection:
        MeasurementRun("foo"),
        IngredientSpecCollection:
        IngredientSpec("foo"),
        IngredientRunCollection:
        IngredientRun(),
        PropertyTemplateCollection:
        PropertyTemplate("bar", bounds=IntegerBounds(0, 1)),
        ParameterTemplateCollection:
        ParameterTemplate("bar", bounds=IntegerBounds(0, 1)),
        ConditionTemplateCollection:
        ConditionTemplate("bar", bounds=IntegerBounds(0, 1))
    }

    for collection, obj in expected.items():
        assert len(obj.uids) == 0
        registered = dataset.register(obj)
        assert len(obj.uids) == 1
        assert len(registered.uids) == 1
        assert basename(dataset.session.calls[-1].path) == basename(
            collection._path_template)
        for pair in obj.uids.items():
            assert pair[1] == registered.uids[pair[0]]
Beispiel #8
0
def test_cursor_paginated_searches(collection, session):
    """
    Tests that search methods using cursor-pagination are hooked up correctly.
    There is no real search logic tested here.
    """
    all_runs = [
        MaterialRunDataFactory(name="foo_{}".format(i)) for i in range(20)
    ]
    fake_request = make_fake_cursor_request_function(all_runs)
    # pretty shady, need to add these methods to the fake session to test their
    # interactions with the actual search methods
    setattr(session, 'get_resource', fake_request)
    setattr(session, 'post_resource', fake_request)
    setattr(session, 'cursor_paged_resource', Session.cursor_paged_resource)

    assert len(list(collection.list_by_name('unused',
                                            per_page=2))) == len(all_runs)
    assert len(list(collection.list_all(per_page=2))) == len(all_runs)
    assert len(list(collection.list_by_tag('unused',
                                           per_page=2))) == len(all_runs)
    assert len(
        list(
            collection.list_by_attribute_bounds(
                {LinkByUIDFactory(): IntegerBounds(1, 5)},
                per_page=2))) == len(all_runs)

    # invalid inputs
    with pytest.raises(TypeError):
        collection.list_by_attribute_bounds([1, 5], per_page=2)
    with pytest.raises(NotImplementedError):
        collection.list_by_attribute_bounds(
            {
                LinkByUIDFactory(): IntegerBounds(1, 5),
                LinkByUIDFactory(): IntegerBounds(1, 5),
            },
            per_page=2)
    with pytest.raises(RuntimeError):
        collection.dataset_id = None
        collection.list_by_name('unused', per_page=2)
def test_bounds_optional():
    """Test that each object template can have passthrough bounds for any of its attributes."""
    def link():
        return LinkByUID(id=str(uuid4()), scope=str(uuid4()))
    for template_type, attribute_args in [
        (MaterialTemplate, [
            ('properties', PropertyTemplate),
        ]),
        (ProcessTemplate, [
            ('conditions', ConditionTemplate),
            ('parameters', ParameterTemplate),
        ]),
        (MeasurementTemplate, [
            ('properties', PropertyTemplate),
            ('conditions', ConditionTemplate),
            ('parameters', ParameterTemplate),
        ]),
    ]:
        kwargs = {}
        for name, attribute_type in attribute_args:
            kwargs[name] = [
                [link(), IntegerBounds(0, 10)],
                link(),
                attribute_type('foo', bounds=IntegerBounds(0, 10)),
                (link(), None)
            ]
        template = template_type(name='foo', **kwargs)
        for name, _ in attribute_args:
            attributes = getattr(template, name)
            assert len(attributes) == 4
            for _, bounds in attributes[1:]:
                assert bounds is None
            dumped = template.dump()
            for _, bounds in dumped[name][1:]:
                assert bounds is None
            assert template_type.build(dumped) == template
Beispiel #10
0
def test_fields_from_property():
    """Test that several fields of the attribute are derived from the property."""
    prop_template = PropertyTemplate(name="cookie eating template", bounds=IntegerBounds(0, 1000))
    cond_template = ConditionTemplate(name="Hunger template",
                                      bounds=CategoricalBounds(["hungry", "full", "peckish"]))
    prop = Property(name="number of cookies eaten",
                    template=prop_template,
                    origin='measured',
                    value=NominalInteger(27))
    cond = Condition(name="hunger level",
                     template=cond_template,
                     origin='specified',
                     value=NominalCategorical("hungry"))

    prop_and_conds = PropertyAndConditions(property=prop, conditions=[cond])
    assert prop_and_conds.name == prop.name
    assert prop_and_conds.template == prop.template
    assert prop_and_conds.origin == prop.origin
    assert prop_and_conds.value == prop.value
def test_contains():
    """Test contains logic."""
    int_bounds = IntegerBounds(0, 2)

    assert int_bounds.contains(IntegerBounds(0, 1))
    assert int_bounds.contains(IntegerBounds(1, 2))
    assert not int_bounds.contains(IntegerBounds(1, 3))
    assert not int_bounds.contains(None)
    with pytest.raises(TypeError):
        int_bounds.contains([0, 1])

    from gemd.entity.value import NominalInteger

    assert int_bounds.contains(NominalInteger(1))
    assert not int_bounds.contains(NominalInteger(5))
def test_incompatible_types():
    """Make sure that incompatible types aren't contained or validated."""
    int_bounds = IntegerBounds(0, 1)

    assert not int_bounds.contains(RealBounds(0.0, 1.0, ''))
Beispiel #13
0
def test_register_all_data_concepts(dataset):
    """Check that register_all registers everything and routes to all collections"""
    bounds = IntegerBounds(0, 1)
    property_template = PropertyTemplate("bar", bounds=bounds)
    parameter_template = ParameterTemplate("bar", bounds=bounds)
    condition_template = ConditionTemplate("bar", bounds=bounds)
    foo_process_template = ProcessTemplate(
        "foo",
        conditions=[[condition_template, bounds]],
        parameters=[[parameter_template, bounds]])
    foo_process_spec = ProcessSpec("foo", template=foo_process_template)
    foo_process_run = ProcessRun("foo", spec=foo_process_spec)
    foo_material_template = MaterialTemplate(
        "foo", properties=[[property_template, bounds]])
    foo_material_spec = MaterialSpec("foo",
                                     template=foo_material_template,
                                     process=foo_process_spec)
    foo_material_run = MaterialRun("foo",
                                   spec=foo_material_spec,
                                   process=foo_process_run)
    baz_template = MaterialTemplate("baz")
    foo_measurement_template = MeasurementTemplate(
        "foo",
        conditions=[[condition_template, bounds]],
        parameters=[[parameter_template, bounds]],
        properties=[[property_template, bounds]])
    foo_measurement_spec = MeasurementSpec("foo",
                                           template=foo_measurement_template)
    foo_measurement_run = MeasurementRun("foo",
                                         spec=foo_measurement_spec,
                                         material=foo_material_run)
    foo_ingredient_spec = IngredientSpec("foo",
                                         material=foo_material_spec,
                                         process=foo_process_spec)
    foo_ingredient_run = IngredientRun(spec=foo_ingredient_spec,
                                       material=foo_material_run,
                                       process=foo_process_run)
    baz_run = MeasurementRun("baz")

    # worst order possible
    expected = {
        foo_ingredient_run: IngredientRunCollection,
        foo_ingredient_spec: IngredientSpecCollection,
        foo_measurement_run: MeasurementRunCollection,
        foo_measurement_spec: MeasurementSpecCollection,
        foo_measurement_template: MeasurementTemplateCollection,
        foo_material_run: MaterialRunCollection,
        foo_material_spec: MaterialSpecCollection,
        foo_material_template: MaterialTemplateCollection,
        foo_process_run: ProcessRunCollection,
        foo_process_spec: ProcessSpecCollection,
        foo_process_template: ProcessTemplateCollection,
        baz_template: MaterialTemplateCollection,
        baz_run: MeasurementRunCollection,
        property_template: PropertyTemplateCollection,
        parameter_template: ParameterTemplateCollection,
        condition_template: ConditionTemplateCollection
    }
    for obj in expected:
        assert len(obj.uids) == 0  # All should be without ids
    registered = dataset.register_all(expected.keys())
    assert len(registered) == len(expected)

    seen_ids = set()
    for obj in expected:
        assert len(obj.uids) == 1  # All should now have exactly 1 id
        for pair in obj.uids.items():
            assert pair not in seen_ids  # All ids are different
            seen_ids.add(pair)
    for obj in registered:
        for pair in obj.uids.items():
            assert pair in seen_ids  # registered items have the same ids

    call_basenames = [
        call.path.split('/')[-2] for call in dataset.session.calls
    ]
    collection_basenames = [
        basename(collection._path_template)
        for collection in expected.values()
    ]
    assert set(call_basenames) == set(collection_basenames)
    assert len(set(call_basenames)) == len(
        call_basenames)  # calls are batched internally

    # spot check order. Does not check every constraint
    assert call_basenames.index(
        basename(
            IngredientRunCollection._path_template)) > call_basenames.index(
                basename(IngredientSpecCollection._path_template))
    assert call_basenames.index(basename(
        MaterialRunCollection._path_template)) > call_basenames.index(
            basename(MaterialSpecCollection._path_template))
    assert call_basenames.index(
        basename(
            MeasurementRunCollection._path_template)) > call_basenames.index(
                basename(MeasurementSpecCollection._path_template))
    assert call_basenames.index(basename(
        ProcessRunCollection._path_template)) > call_basenames.index(
            basename(ProcessSpecCollection._path_template))
    assert call_basenames.index(basename(
        MaterialSpecCollection._path_template)) > call_basenames.index(
            basename(MaterialTemplateCollection._path_template))
    assert call_basenames.index(
        basename(
            MeasurementSpecCollection._path_template)) > call_basenames.index(
                basename(MeasurementTemplateCollection._path_template))
    assert call_basenames.index(basename(
        ProcessSpecCollection._path_template)) > call_basenames.index(
            basename(ProcessTemplateCollection._path_template))
    assert call_basenames.index(basename(
        MaterialSpecCollection._path_template)) > call_basenames.index(
            basename(ProcessSpecCollection._path_template))
    assert call_basenames.index(basename(
        MaterialSpecCollection._path_template)) > call_basenames.index(
            basename(MeasurementSpecCollection._path_template))
    assert call_basenames.index(
        basename(MeasurementTemplateCollection._path_template)
    ) > call_basenames.index(
        basename(ConditionTemplateCollection._path_template))
    assert call_basenames.index(
        basename(MeasurementTemplateCollection._path_template)
    ) > call_basenames.index(
        basename(ParameterTemplateCollection._path_template))
    assert call_basenames.index(
        basename(
            MaterialTemplateCollection._path_template)) > call_basenames.index(
                basename(PropertyTemplateCollection._path_template))
Beispiel #14
0
def test_parameter_template():
    """Test creation and serde of parameter templates."""
    bounds = IntegerBounds(-3, 8)
    template = ParameterTemplate("Position knob", bounds=bounds, tags=["Tag1", "A::B::C"])
    assert template.uids is not None  # uids should be added automatically
    assert ParameterTemplate.build(template.dump()) == template