From 9b44ec7bc64d69f97670d58507d1016201322ae6 Mon Sep 17 00:00:00 2001 From: Charles Baynham Date: Thu, 23 Jul 2020 11:49:21 +0100 Subject: [PATCH] parameters: Allow forcing a NumberValue to return a float Signed-off-by: Charles Baynham --- RELEASE_NOTES.rst | 1 + artiq/language/environment.py | 36 +++++++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 3a9a6d21a..7b9899d71 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -23,6 +23,7 @@ Highlights: * Experiment results are now always saved to HDF5, even if run() fails. * Core device: ``panic_reset 1`` now correctly resets the kernel CPU as well if communication CPU panic occurs. +* NumberValue accepts a ``type`` parameter specifying the output as ``int`` or ``float`` Breaking changes: diff --git a/artiq/language/environment.py b/artiq/language/environment.py index fddae667f..f7aab5502 100644 --- a/artiq/language/environment.py +++ b/artiq/language/environment.py @@ -100,10 +100,9 @@ class EnumerationValue(_SimpleArgProcessor): class NumberValue(_SimpleArgProcessor): """An argument that can take a numerical value. - If ndecimals = 0, scale = 1 and step is integer, then it returns - an integer value. Otherwise, it returns a floating point value. - The simplest way to represent an integer argument is - ``NumberValue(step=1, ndecimals=0)``. + If ``type=="auto"``, the result will be a ``float`` unless + ndecimals = 0, scale = 1 and step is an integer. Setting ``type`` to + ``int`` will also result in an error unless these conditions are met. When ``scale`` is not specified, and the unit is a common one (i.e. defined in ``artiq.language.units``), then the scale is obtained from @@ -126,9 +125,13 @@ class NumberValue(_SimpleArgProcessor): :param min: The minimum value of the argument. :param max: The maximum value of the argument. :param ndecimals: The number of decimals a UI should use. + :param type: Type of this number. Accepts ``"float"``, ``"int"`` or + ``"auto"``. Defaults to ``"auto"``. """ + valid_types = ["auto", "float", "int"] + def __init__(self, default=NoDefault, unit="", scale=None, - step=None, min=None, max=None, ndecimals=2): + step=None, min=None, max=None, ndecimals=2, type="auto"): if scale is None: if unit == "": scale = 1.0 @@ -146,14 +149,34 @@ class NumberValue(_SimpleArgProcessor): self.min = min self.max = max self.ndecimals = ndecimals + self.type = type + + if self.type not in NumberValue.valid_types: + raise TypeError("type must be 'float', 'int' or 'auto'") + + if self.type == "int" and not self._is_int_compatible(): + raise ValueError(("Value marked as integer but settings are " + "not compatible. Please set ndecimals = 0, " + "scale = 1 and step to an integer")) super().__init__(default) - def _is_int(self): + def _is_int_compatible(self): + ''' + Are the settings other than `type` compatible with this being + an integer? + ''' return (self.ndecimals == 0 and int(self.step) == self.step and self.scale == 1) + def _is_int(self): + ''' + Will this argument return an integer? + ''' + return (self.type == "int" + or (self.type == "auto" and self._is_int_compatible())) + def process(self, x): if self._is_int(): return int(x) @@ -170,6 +193,7 @@ class NumberValue(_SimpleArgProcessor): d["min"] = self.min d["max"] = self.max d["ndecimals"] = self.ndecimals + d["type"] = self.type return d