def update_metadata(comp_name, key_val_str): """ update the metadata of the given component with the given key/value key_val_str (dict str->str): key name -> value as a string """ component = get_component(comp_name) md = {} for key_name, str_val in key_val_str.items(): # Check that the metadata is a valid one. It's a bit tricky as there is no # "official" list. But we look at the ones defined in model.MD_* for n, v in inspect.getmembers(model, lambda m: isinstance(m, str)): if n.startswith("MD_") and v == key_name: key = key_name break else: # fallback to looking for MD_{key_name} try: key = getattr(model, "MD_%s" % key_name) except AttributeError: raise ValueError("Metadata key '%s' is unknown" % key_name) md[key] = convertToObject(str_val) try: component.updateMetadata(md) except Exception as exc: raise IOError("Failed to update metadata of %s to %s: %s" % (comp_name, md, exc))
def set_attr(comp_name, attr_val_str): """ set the value of vigilant attribute of the given component. attr_val_str (dict str->str): attribute name -> value as a string """ component = get_component(comp_name) for attr_name, str_val in attr_val_str.items(): try: attr = getattr(component, attr_name) except Exception: raise ValueError("Failed to find attribute '%s' on component '%s'" % (attr_name, comp_name)) if not isinstance(attr, model.VigilantAttributeBase): raise ValueError("'%s' is not a vigilant attribute of component %s" % (attr_name, comp_name)) new_val = convertToObject(str_val) # Special case for floats, due to rounding error, it's very hard to put the # exact value if it's an enumerated VA. So just pick the closest one in this # case. if isinstance(new_val, float) and ( hasattr(attr, "choices") and isinstance(attr.choices, collections.Iterable)): orig_val = new_val new_val = util.find_closest(new_val, attr.choices) if new_val != orig_val: logging.debug("Adjusting value to %s", new_val) try: attr.value = new_val except Exception as exc: raise IOError("Failed to set %s.%s = '%s': %s" % (comp_name, attr_name, str_val, exc))
def test_convertToObject_good(self): """ check various inputs and compare to expected output for values that should work """ # example value / input str / expected output tc = [("-1561", -1561), ("0.123", 0.123), ("true", True), ("c: 6,d: 1.3", {"c": 6., "d":1.3}), ("-9, -8", [-9, -8]), (" 9, -8", [9, -8]), ("0, -8, -15.e-3, 6.", [0, -8, -15e-3, 6.0]), ("0.1", 0.1), ("[aa,bb]", ["aa", "bb"]), # TODO: more complicated but nice to support for the user # ("256 x 256 px", (256, 256)), # ("21 x 0.2 m", (21, 0.2)), ("", None), ("{5: }", {5: None}), # Should it fail? ("-1, 63, 12", [-1, 63, 12]), # NotifyingList becomes a list ("9.3, -8", [9.3, -8]), # Note: we don't support SI prefixes ("[aa, c a]", ["aa", "c a"]), ] for str_val, expo in tc: out = convertToObject(str_val) self.assertEqual(out, expo, "Testing with '%s' -> %s" % (str_val, out))
def move_abs(comp_name, axis_name, str_position): """ move (in absolute) the axis of the given component to the specified position in µm """ # for safety reason, we use µm instead of meters, as it's harder to type a # huge distance try: component = get_component(comp_name) except LookupError: logging.error("Failed to find actuator '%s'", comp_name) return 127 except: logging.error("Failed to contact the back-end") return 127 try: if axis_name not in component.axes: logging.error("Actuator %s has not axis '%s'", comp_name, axis_name) return 129 ad = component.axes[axis_name] except (TypeError, AttributeError): logging.error("Component %s is not an actuator", comp_name) return 127 # TODO: check whether the component supports absolute positioning if ad.unit == "m": try: position = float(str_position) * 1e-6 # µm -> m except ValueError: logging.error("Distance '%s' cannot be converted to a number", str_position) return 127 # compare to the current position, to see if the new position sounds reasonable cur_pos = component.position.value[axis_name] if abs(cur_pos - position) > MAX_DISTANCE: logging.error("Distance of move of %g m is too big (> %g m)", abs(cur_pos - position), MAX_DISTANCE) return 129 else: position = convertToObject(str_position) try: m = component.moveAbs({axis_name: position}) m.result() except Exception: logging.error("Failed to move axis %s of component %s", axis_name, comp_name) return 127 return 0
def test_convertToObject_bad(self): """ check various inputs and compare to expected output for values that should raise an exception """ # example value / input str tc = [("{5:"), ("[5.3"), # ("5,6]"), # TODO ] for str_val in tc: with self.assertRaises((ValueError, TypeError)): out = convertToObject(str_val)
def move(comp_name, axis_name, str_distance): """ move (relatively) the axis of the given component by the specified amount of µm """ # for safety reason, we use µm instead of meters, as it's harder to type a # huge distance try: component = get_component(comp_name) except LookupError: logging.error("Failed to find actuator '%s'", comp_name) return 127 except: logging.error("Failed to contact the back-end") return 127 try: if axis_name not in component.axes: logging.error("Actuator %s has not axis '%s'", comp_name, axis_name) return 129 ad = component.axes[axis_name] except (TypeError, AttributeError): logging.error("Component %s is not an actuator", comp_name) return 127 if ad.unit == "m": try: distance = float(str_distance) * 1e-6 # µm -> m except ValueError: logging.error("Distance '%s' cannot be converted to a number", str_distance) return 127 if abs(distance) > MAX_DISTANCE: logging.error("Distance of %f m is too big (> %f m)", abs(distance), MAX_DISTANCE) return 129 else: distance = convertToObject(str_distance) try: m = component.moveRel({axis_name: distance}) m.result() except Exception: logging.error("Failed to move axis %s of component %s", axis_name, comp_name) return 127 return 0
def set_attr(comp_name, attr_name, str_val): """ set the value of vigilant attribute of the given component using the type of the current value of the attribute. """ try: component = get_component(comp_name) except LookupError: logging.error("Failed to find component '%s'", comp_name) return 127 except: logging.error("Failed to contact the back-end") return 127 try: attr = getattr(component, attr_name) except: logging.error("Failed to find attribute '%s' on component '%s'", attr_name, comp_name) return 129 if not isinstance(attr, model.VigilantAttributeBase): logging.error("'%s' is not a vigilant attribute of component '%s'", attr_name, comp_name) return 129 try: new_val = convertToObject(str_val) except Exception: return 127 # Special case for floats, due to rounding error, it's very hard to put the # exact value if it's an enumerated VA. So just pick the closest one in this # case. if isinstance(new_val, float) and (hasattr(attr, "choices") and isinstance( attr.choices, collections.Iterable)): orig_val = new_val new_val = util.find_closest(new_val, attr.choices) if new_val != orig_val: logging.debug("Adjusting value to %s", new_val) try: attr.value = new_val except: logging.exception("Failed to set %s.%s = '%s'", comp_name, attr_name, str_val) return 127 return 0
def set_attr(comp_name, attr_name, str_val): """ set the value of vigilant attribute of the given component using the type of the current value of the attribute. """ try: component = get_component(comp_name) except LookupError: logging.error("Failed to find component '%s'", comp_name) return 127 except: logging.error("Failed to contact the back-end") return 127 try: attr = getattr(component, attr_name) except: logging.error("Failed to find attribute '%s' on component '%s'", attr_name, comp_name) return 129 if not isinstance(attr, model.VigilantAttributeBase): logging.error("'%s' is not a vigilant attribute of component '%s'", attr_name, comp_name) return 129 try: new_val = convertToObject(str_val) except Exception: return 127 # Special case for floats, due to rounding error, it's very hard to put the # exact value if it's an enumerated VA. So just pick the closest one in this # case. if isinstance(new_val, float) and ( hasattr(attr, "choices") and isinstance(attr.choices, collections.Iterable)): orig_val = new_val new_val = util.find_closest(new_val, attr.choices) if new_val != orig_val: logging.debug("Adjusting value to %s", new_val) try: attr.value = new_val except: logging.exception("Failed to set %s.%s = '%s'", comp_name, attr_name, str_val) return 127 return 0
def move_abs(comp_name, axis_name, str_position): """ move (in absolute) the axis of the given component to the specified position in µm """ component = get_component(comp_name) try: if axis_name not in component.axes: raise ValueError("Actuator %s has no axis '%s'" % (comp_name, axis_name)) ad = component.axes[axis_name] except (TypeError, AttributeError): raise ValueError("Component %s is not an actuator" % comp_name) if ad.unit == "m": try: position = float(str_position) except ValueError: raise ValueError("Position '%s' cannot be converted to a number" % str_position) # compare to the current position, to see if the new position sounds reasonable cur_pos = component.position.value[axis_name] if abs(cur_pos - position) > MAX_DISTANCE: raise IOError("Distance of %f m is too big (> %f m)" % (abs(cur_pos - position), MAX_DISTANCE)) else: position = convertToObject(str_position) try: logging.info(u"Will move %s.%s to %s", comp_name, axis_name, units.readable_str(position, ad.unit, sig=3)) except Exception: pass try: m = component.moveAbs({axis_name: position}) m.result() except Exception as exc: raise IOError("Failed to move axis %s of component %s: %s" % (axis_name, comp_name, exc))
def move(comp_name, axis_name, str_distance): """ move (relatively) the axis of the given component by the specified amount of µm """ # for safety reason, we use µm instead of meters, as it's harder to type a # huge distance component = get_component(comp_name) try: if axis_name not in component.axes: raise ValueError("Actuator %s has no axis '%s'" % (comp_name, axis_name)) ad = component.axes[axis_name] except (TypeError, AttributeError): raise ValueError("Component %s is not an actuator" % comp_name) if ad.unit == "m": try: distance = float(str_distance) * 1e-6 # µm -> m except ValueError: raise ValueError("Distance '%s' cannot be converted to a number" % str_distance) if abs(distance) > MAX_DISTANCE: raise IOError("Distance of %f m is too big (> %f m)" % (abs(distance), MAX_DISTANCE)) else: distance = convertToObject(str_distance) try: logging.info(u"Will move %s.%s by %s", comp_name, axis_name, units.readable_str(distance, ad.unit, sig=3)) except Exception: pass try: m = component.moveRel({axis_name: distance}) m.result() except Exception as exc: raise IOError("Failed to move axis %s of component %s: %s" % (axis_name, comp_name, exc))
def set_attr(comp_name, attr_val_str): """ set the value of vigilant attribute of the given component. attr_val_str (dict str->str): attribute name -> value as a string """ component = get_component(comp_name) for attr_name, str_val in attr_val_str.items(): try: attr = getattr(component, attr_name) except Exception: raise ValueError( "Failed to find attribute '%s' on component '%s'" % (attr_name, comp_name)) if not isinstance(attr, model.VigilantAttributeBase): raise ValueError( "'%s' is not a vigilant attribute of component %s" % (attr_name, comp_name)) new_val = convertToObject(str_val) # Special case for floats, due to rounding error, it's very hard to put the # exact value if it's an enumerated VA. So just pick the closest one in this # case. if isinstance(new_val, float) and (hasattr(attr, "choices") and isinstance( attr.choices, collections.Iterable)): orig_val = new_val new_val = util.find_closest(new_val, attr.choices) if new_val != orig_val: logging.debug("Adjusting value to %s", new_val) try: attr.value = new_val except Exception as exc: raise IOError("Failed to set %s.%s = '%s': %s" % (comp_name, attr_name, str_val, exc))