def str_to_value(text, va): """ Attempt to fit the given text as a value for the given VA text (str): "Free-form" entry from a user va (Vigilant Attribute): the VA that would receive the value return (value): a value that might fit the VA raise ValueError: if cannot convert """ logging.debug("Parsing free text value %s", text) va_val = va.value # Try to find a good corresponding value inside the string if isinstance(va_val, collections.Iterable) and text.endswith(va.unit): _, str_si, _ = decompose_si_prefix("1" + text[-(len(va.unit) + 1):], unit=va.unit) str_val = text else: str_val, str_si, _ = decompose_si_prefix(text, unit=va.unit) new_val = reproduce_typed_value(va_val, str_val) # In case of list, be lenient by dropping the extra values if it's too many if isinstance(new_val, collections.Iterable): new_val = new_val[:len(va_val)] if new_val and isinstance(new_val[0], numbers.Real): new_val = tuple(si_scale_val(v, str_si) for v in new_val) else: # If an SI prefix was found, scale the new value if isinstance(new_val, numbers.Real): new_val = si_scale_val(new_val, str_si) return new_val
def cb_get(ctrl=value_ctrl, va=va, u=unit): ctrl_value = ctrl.GetValue() # Try to use the predefined value if it's available i = ctrl.GetSelection() # Warning: if the text contains an unknown value, GetSelection will # not return wx.NOT_FOUND (as expected), but the last selection value if i != wx.NOT_FOUND and ctrl.Items[i] == ctrl_value: logging.debug("Getting item value %s from combobox control", ctrl.GetClientData(i)) return ctrl.GetClientData(i) else: logging.debug("Parsing combobox free text value %s", ctrl_value) va_val = va.value # Try to find a good corresponding value inside the string # Try and find an SI prefix str_val, str_si, _ = decompose_si_prefix(ctrl_value, unit=u) new_val = reproduce_typed_value(va_val, str_val) if isinstance(new_val, collections.Iterable): # be less picky, by shortening the number of values if it's too many new_val = new_val[:len(va_val)] # If an SI prefix was found, scale the new value new_val = si_scale_val(new_val, str_si) # if it ends up being the same value as before the combobox will not update, so # force it now if va_val == new_val: cb_set(va_val) return new_val
def test_reproduceTypedValue_good(self): """ check various inputs and compare to expected output for values that should work """ lva = model.ListVA([12, -3]) # example value / input str / expected output tc = [(3, "-1561", -1561), (-9.3, "0.123", 0.123), (False, "true", True), ({"a": 12.5, "b": 3.}, "c:6,d:1.3", {"c": 6., "d":1.3}), ((-5, 0, 6), " 9, -8", (9, -8)), # we don't force to be the same size ((1.2, 0.0), "0, -8, -15e-3, 6.", (0.0, -8.0, -15e-3, 6.0)), ([1.2, 0.0], "0.1", [0.1]), (("cou", "bafd"), "aa,bb", ("aa", "bb")), # more complicated but nice to support for the user ((1200, 256), "256 x 256 px", (256, 256)), ((1.2, 256), " 21 x 0.2 m", (21, 0.2)), ([-5, 0, 6], "9,, -8", [9, -8]), ((1.2, 0.0), "", tuple()), (lva.value, "-1, 63, 12", [-1, 63, 12]), # NotifyingList becomes a list ((-5, 0, 6), "9.3, -8", (9, 3, -8)), # maybe this shouldn't work? # Note: we don't support SI prefixes (("cou",), "aa, c a", ("aa", " c a")), # TODO: need to see if spaces should be kept or trimmed ] for ex_val, str_val, expo in tc: out = reproduce_typed_value(ex_val, str_val) self.assertEqual(out, expo, "Testing with %s / '%s' -> %s" % (ex_val, str_val, out))
def cb_get(ctrl=value_ctrl, va=va, u=unit): ctrl_value = ctrl.GetValue() # Try to use the predefined value if it's available i = ctrl.GetSelection() # Warning: if the text contains an unknown value, GetSelection will # not return wx.NOT_FOUND (as expected), but the last selection value if i != wx.NOT_FOUND and ctrl.Items[i] == ctrl_value: logging.debug("Getting item value %s from combobox control", ctrl.GetClientData(i)) return ctrl.GetClientData(i) else: logging.debug("Parsing combobox free text value %s", ctrl_value) va_val = va.value # Try to find a good corresponding value inside the string str_val, str_si, _ = decompose_si_prefix(ctrl_value, unit=u) try: new_val = reproduce_typed_value(va_val, str_val) except (ValueError, TypeError): logging.warning("Value %s couldn't be understood", str_val, exc_info=True) new_val = va_val # To force going back to last value # In case of list, be lenient by dropping the extra values if it's too many if isinstance(new_val, collections.Iterable): new_val = new_val[:len(va_val)] # If an SI prefix was found, scale the new value new_val = si_scale_val(new_val, str_si) # if it ends up being the same value as before the combobox will # not update, so force it now if va_val == new_val: cb_set(va_val) return new_val
def test_reproduceTypedValue_bad(self): """ check various inputs and compare to expected output for values that should raise an exception """ # example value / input str tc = [(3, "-"), (-9, "0.123"), (False, "56"), ({"a": 12.5, "b": 3.}, "6,1.3"), (9.3, "0, 123"), ] for ex_val, str_val in tc: with self.assertRaises((ValueError, TypeError)): out = reproduce_typed_value(ex_val, str_val)
def test_reproduceTypedValue_bad(self): """ check various inputs and compare to expected output for values that should raise an exception """ # example value / input str tc = [ (3, "-"), (-9, "0.123"), (False, "56"), ({ "a": 12.5, "b": 3. }, "6,1.3"), (9.3, "0, 123"), ] for ex_val, str_val in tc: with self.assertRaises((ValueError, TypeError)): out = reproduce_typed_value(ex_val, str_val)
def test_reproduceTypedValue_good(self): """ check various inputs and compare to expected output for values that should work """ lva = model.ListVA([12, -3]) # example value / input str / expected output tc = [ (3, "-1561", -1561), (-9.3, "0.123", 0.123), (False, "true", True), ({ "a": 12.5, "b": 3. }, "c:6,d:1.3", { "c": 6., "d": 1.3 }), ((-5, 0, 6), " 9, -8", (9, -8)), # we don't force to be the same size ((1.2, 0.0), "0, -8, -15e-3, 6.", (0.0, -8.0, -15e-3, 6.0)), ([1.2, 0.0], "0.1", [0.1]), (("cou", "bafd"), "aa,bb", ("aa", "bb")), # more complicated but nice to support for the user ((1200, 256), "256 x 256 px", (256, 256)), ((1.2, 256), " 21 x 0.2 m", (21, 0.2)), ([-5, 0, 6], "9,, -8", [9, -8]), ((1.2, 0.0), "", tuple()), (lva.value, "-1, 63, 12", [-1, 63, 12]), # NotifyingList becomes a list ((-5, 0, 6), "9.3, -8", (9, 3, -8)), # maybe this shouldn't work? # Note: we don't support SI prefixes (("cou", ), "aa, c a", ("aa", " c a") ), # TODO: need to see if spaces should be kept or trimmed ] for ex_val, str_val, expo in tc: out = reproduce_typed_value(ex_val, str_val) self.assertEqual( out, expo, "Testing with %s / '%s' -> %s" % (ex_val, str_val, out))
def str_to_value(text, va): """ Attempt to fit the given text as a value for the given VA text (str): "Free-form" entry from a user va (Vigilant Attribute): the VA that would receive the value return (value): a value that might fit the VA raise ValueError: if cannot convert """ logging.debug("Parsing free text value %s", text) va_val = va.value # Try to find a good corresponding value inside the string str_val, str_si, _ = decompose_si_prefix(text, unit=va.unit) new_val = reproduce_typed_value(va_val, str_val) # In case of list, be lenient by dropping the extra values if it's too many if isinstance(new_val, collections.Iterable): new_val = new_val[:len(va_val)] # If an SI prefix was found, scale the new value # TODO: support iterables too if isinstance(new_val, numbers.Real): new_val = si_scale_val(new_val, str_si) return new_val
def main(args): """ Handles the command line arguments args is the list of arguments passed return (int): value to return to the OS as program exit code """ # arguments handling parser = argparse.ArgumentParser( description="SEM fluorescence bleaching map") parser.add_argument( "--dt", dest="dt", type=float, required=True, help="ebeam (bleaching) dwell time in s (for each sub-pixel)") parser.add_argument( "--dtsem", dest="dtsem", type=float, required=True, help="SEM dwell time in s, for taking the SEM image after " "bleaching procedure") parser.add_argument("--pxs", dest="pxs", type=float, required=True, help="distance between 2 consecutive spots in nm") parser.add_argument("--subpx", dest="subpx", type=int, default=1, help="number of sub-pixels scanned by the ebeam for " "each pixel acquired by the CCD. Must be a " "square of an integer.") parser.add_argument("--gridpitch", dest="gridpitch", type=int, default=0, help="pitch for gridscanning in number of SR pixels." "Setting pitch to 0 disables gridscanning.") parser.add_argument("--roi", dest="roi", required=True, help="e-beam ROI positions (ltrb, relative to the SEM " "field of view)") parser.add_argument( "--lpower", dest="lpower", type=float, default=0.02, help="excitation light power on the first fluorescence pixel (in W).") parser.add_argument("--emission", dest="emission", type=int, default=0, help="emissions source (numbered from 0 to n-1) used " "for the SR pixels.") parser.add_argument( "--exptime", dest="exptime", type=float, default=2.0, help="exposure time used for the SR pixels (in seconds).") parser.add_argument( "--ovw-power", dest="olpower", type=float, nargs="+", default=[], help="excitation light power used for overview image" "that is acquired before and after the scan. There" "can be several power values corresponding to different" "emission sources, each of them will be used" "successively") parser.add_argument("--ovw-emission", dest="oemission", type=int, nargs="+", default=[], help="emissions source (numbered from 0 to n-1) used " "for overview image that is acquired before and " "after the scan. There can be several emission sources" "each of them will be used successively") parser.add_argument("--ovw-exp-time", dest="oexptime", type=float, nargs="+", default=[], help="exposure time that is used for overview image" "that is acquired before and after the scan." "There can be several exposure times corresponding" "to different emission sources and they will be used " "successively") parser.add_argument("--output", dest="filename", required=True, help="name of the output file. It should finish by" ".h5 (for HDF5) or .tiff (for TIFF).") parser.add_argument("--drift", dest="drift", type=float, default=None, help="apply drift correction every nth SR pixel") parser.add_argument( "--anchor", dest="anchor", default=None, help="top-left and bottom-right points of the anchor region") options = parser.parse_args(args[1:]) roi = conversion.reproduce_typed_value([1.0], options.roi) if not all(0 <= r <= 1 for r in roi): raise ValueError("roi values must be between 0 and 1") if not len(options.olpower) == len(options.oemission) == len( options.oexptime): raise ValueError( "overviewlightpower, overviewlightemissions and overviewexposuretime should have the same number of arguments." ) if options.anchor is None or options.drift is None: anchor = None else: anchor = conversion.reproduce_typed_value([1.0], options.anchor) if not all(0 <= a <= 1 for a in anchor): raise ValueError("anchor values must be between 0 and 1") a = Acquirer(options.dt, options.dtsem, roi, options.pxs * 1e-9, options.subpx, options.gridpitch, options.lpower, options.emission, options.exptime, options.olpower, options.oemission, options.oexptime, options.drift, anchor) a.acquire(options.filename)