def test_invalid_constructor(): """Test types for constructor.""" with pytest.raises(ValueError): CategoricalBounds(categories="foo") with pytest.raises(ValueError): CategoricalBounds(categories={1, 2})
def test_contains(): """Test basic contains logic.""" bounds = CategoricalBounds(categories={"spam", "eggs"}) assert bounds.contains(CategoricalBounds(categories={"spam"})) assert not bounds.contains(CategoricalBounds(categories={"spam", "foo"})) assert not bounds.contains(RealBounds(0.0, 2.0, '')) assert not bounds.contains(None) with pytest.raises(TypeError): bounds.contains({"spam", "eggs"})
def test_categories(): """Test categories setter.""" assert CategoricalBounds().categories == set() assert CategoricalBounds(categories={"foo", "bar"}).categories == { "foo", "bar" } assert CategoricalBounds(categories=["foo", "bar"]).categories == { "foo", "bar" }
def test_numpy(): """Test that ndarrays, Series work as well.""" assert len(array_like()) < 5 # In case we extend at some point if len(array_like()) > 2: # Test numpy import numpy as np np_bounds = CategoricalBounds(np.array(["spam", "eggs"], dtype=object)) np_copy = loads(dumps(np_bounds)) assert np_copy == np_bounds if len(array_like()) > 3: # Test numpy import pandas as pd pd_bounds = CategoricalBounds(pd.Series(["spam", "eggs"])) pd_copy = loads(dumps(pd_bounds)) assert pd_copy == pd_bounds
def test_object_template_serde(): """Test serde of an object template.""" length_template = PropertyTemplate("Length", RealBounds(2.0, 3.5, 'cm')) sub_bounds = RealBounds(2.5, 3.0, 'cm') color_template = PropertyTemplate("Color", 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", RealBounds(0.1, 0.11, 'MPa')) index_template = ParameterTemplate("index", 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 proc_template.conditions[0][0] = LinkByUID('id', pressure_template.uids['id']) assert ProcessTemplate.build(proc_template.dump()) == proc_template
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) assert len(flat) == 2, "Expected 2 flattened objects"
def test_object_template_validation(): """Test that attribute templates are validated against given bounds.""" length_template = PropertyTemplate("Length", RealBounds(2.0, 3.5, 'cm')) dial_template = ConditionTemplate("dial", IntegerBounds(0, 5)) color_template = ParameterTemplate( "Color", CategoricalBounds(["red", "green", "blue"])) 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)]])
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 make_templates(): """Build all templates needed for the table.""" tmpl = dict() # Attribute Templates attribute_feed = { "Formula": [ PropertyTemplate, CompositionBounds(components=EmpiricalFormula.all_elements()) ], "Crystallinity": [ ConditionTemplate, CategoricalBounds( ['Amorphous', 'Polycrystalline', 'Single crystalline']) ], "Color": [ PropertyTemplate, CategoricalBounds([ 'Amber', 'Black', 'Blue', 'Bluish', 'Bronze', 'Brown', 'Brown-Black', 'Copper-Red', 'Dark Brown', 'Dark Gray', 'Dark Green', 'Dark Red', 'Gray', 'Light Gray', 'Ocher', 'Orange', 'Orange-Red', 'Pale Yellow', 'Red', 'Red-Yellow', 'Violet', 'White', 'Yellow', 'Yellow-Orange', 'Yellow-White' ]) ], "Band gap": [ PropertyTemplate, RealBounds(lower_bound=0.001, upper_bound=100, default_units='eV') ], "Temperature": [ ConditionTemplate, RealBounds(lower_bound=1, upper_bound=1000, default_units='K') ], "Temperature derivative of band gap": [ PropertyTemplate, RealBounds(lower_bound=-0.01, upper_bound=0.01, default_units='eV/K') ], "Lasing": [PropertyTemplate, CategoricalBounds(['True', 'False'])], "Cathodoluminescence": [PropertyTemplate, CategoricalBounds(['True', 'False'])], "Mechanical luminescence": [PropertyTemplate, CategoricalBounds(['True', 'False'])], "Photoluminescence": [PropertyTemplate, CategoricalBounds(['True', 'False'])], "Electroluminescence": [PropertyTemplate, CategoricalBounds(['True', 'False'])], "Thermoluminescence": [PropertyTemplate, CategoricalBounds(['True', 'False'])], "Morphology": [ConditionTemplate, CategoricalBounds(['Thin film', 'Bulk'])], "Electric field polarization": [ ConditionTemplate, CategoricalBounds([ 'Parallel to A axis', 'Parallel to B axis', 'Parallel to C axis', 'Perpendicular to B axis', 'Perpendicular to C axis' ]) ], "Phase": [ ConditionTemplate, CategoricalBounds([ 'A', 'B', 'B1', 'B2', 'Fused quartz', 'Natural diamond', 'Rutile', 'Sapphire', 'Synthetic quartz' ]) ], "Crystal system": [ ConditionTemplate, CategoricalBounds([ 'Cubic', 'Hexagonal', 'Orthorhombic', 'Tetragonal', 'Trigonal' ]) ], "Transition": [ ConditionTemplate, CategoricalBounds(['Direct', 'Excitonic', 'Indirect']) ], "Bands": [ ConditionTemplate, CategoricalBounds([ 'G1 to X1', 'G15 to G1', 'G15 to X1', 'G25 to G1', 'G25 to G12', 'G25 to G15', 'G6 to G8', 'G8 to G6+', 'L6+ to L6-' ]) ] } for (name, (typ, bounds)) in attribute_feed.items(): assert name not in tmpl tmpl[name] = typ(name=name, bounds=bounds, uids={DEMO_SCOPE + '-template': name}, tags=['citrine::demo::template::attribute']) # Object Templates object_feed = { "Sample preparation": [ProcessTemplate, dict()], "Chemical": [MaterialTemplate, { "properties": [tmpl["Formula"]] }], "Band gap measurement": [ MeasurementTemplate, { "properties": [ tmpl["Band gap"], tmpl["Temperature derivative of band gap"], tmpl["Color"], tmpl["Lasing"], tmpl["Cathodoluminescence"], tmpl["Mechanical luminescence"], tmpl["Photoluminescence"], tmpl["Electroluminescence"], tmpl["Thermoluminescence"] ], "conditions": [ tmpl["Temperature"], tmpl["Crystallinity"], tmpl["Morphology"], tmpl["Electric field polarization"], tmpl["Phase"], tmpl["Crystal system"], tmpl["Transition"], tmpl["Bands"] ] } ], } for (name, (typ, kw_args)) in object_feed.items(): assert name not in tmpl tmpl[name] = typ(name=name, uids={DEMO_SCOPE + '-template': name}, tags=['citrine::demo::template::object'], **kw_args) return tmpl
from taurus.entity.bounds.categorical_bounds import CategoricalBounds from taurus.entity.bounds.real_bounds import RealBounds from taurus.entity.value.uniform_real import UniformReal from taurus.entity.template.attribute_template import AttributeTemplate from taurus.entity.template.property_template import PropertyTemplate from taurus.client.json_encoder import dumps, loads class SampleAttributeTemplate(AttributeTemplate): """A class to flex the base attribute template.""" typ = "sample_attribute_template" cat_bounds = CategoricalBounds(categories={"a", "b", "c"}) def test_name_is_a_string(): """Test that name is a string.""" with pytest.raises(ValueError) as error: SampleAttributeTemplate(name=42, bounds=cat_bounds) assert "must be a string" in str(error.value) def test_invalid_bounds(): """Test that invalid bounds throw the appropriate error.""" with pytest.raises(ValueError): SampleAttributeTemplate(name="name") # Must have a bounds with pytest.raises(TypeError):
def test_property_template(): """Test creation and serde of condition templates.""" bounds = CategoricalBounds(['solid', 'liquid', 'gas']) template = PropertyTemplate("State", bounds=bounds, uids={'my_id': '0'}) assert PropertyTemplate.build(template.dump()) == template
name="kinematic viscosity", bounds=RealBounds(lower_bound=0.0, upper_bound=10.0**40, default_units="m^2 / s") ) } known_conditions = { "temperature": ConditionTemplate( name="temperature", bounds=RealBounds(lower_bound=0.0, upper_bound=1000.0, default_units='K') ) } known_parameters = { "knob_2_setting": ParameterTemplate( name="knob_2_setting", bounds=CategoricalBounds(categories={"low", "medium", "high"}) ) } def _parse_value(val): """Example field-parsing logic.""" # If the string is complicated, split it up and try to get uncertainty and/or units if isinstance(val, str) and len(val.split()) > 1: toks = val.split() mean = float(toks[0]) std = -1 if toks[1] in {"+-", "+/-"}: std = float(toks[2]) try:
def test_json(): """Test that serialization works (categories is encoded as a list).""" bounds = CategoricalBounds(categories={"spam", "eggs"}) copy = loads(dumps(bounds)) assert copy == bounds