Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: dd7920f0c3ea
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 9e29a4650ac0
Choose a head ref
  • 3 commits
  • 4 files changed
  • 1 contributor

Commits on Jul 18, 2015

  1. Copy the full SHA
    657f198 View commit details
  2. Copy the full SHA
    5f95a30 View commit details
  3. Copy the full SHA
    9e29a46 View commit details
Showing with 182 additions and 5 deletions.
  1. +1 −1 artiq/gui/displays.py
  2. +60 −1 artiq/gui/explorer.py
  3. +103 −3 artiq/language/environment.py
  4. +18 −0 examples/master/repository/arguments_demo.py
2 changes: 1 addition & 1 deletion artiq/gui/displays.py
Original file line number Diff line number Diff line change
@@ -64,7 +64,7 @@ def update_data(self, data):
try:
n = float(data[result])
except:
n = 0.0
n = "---"
self.number.display(n)


61 changes: 60 additions & 1 deletion artiq/gui/explorer.py
Original file line number Diff line number Diff line change
@@ -33,8 +33,67 @@ def get_argument_value(self):
return pyon.decode(self.text())


class _BooleanEntry(QtGui.QCheckBox):
def __init__(self, procdesc):
QtGui.QCheckBox.__init__(self)
if "default" in procdesc:
self.setChecked(procdesc["default"])

def get_argument_value(self):
return self.isChecked()


class _EnumerationEntry(QtGui.QComboBox):
def __init__(self, procdesc):
QtGui.QComboBox.__init__(self)
self.choices = procdesc["choices"]
self.addItems(self.choices)
if "default" in procdesc:
try:
idx = self.choices.index(procdesc["default"])
except:
pass
else:
self.setCurrentIndex(idx)

def get_argument_value(self):
return self.choices[self.currentIndex()]


class _NumberEntry(QtGui.QDoubleSpinBox):
def __init__(self, procdesc):
QtGui.QDoubleSpinBox.__init__(self)
if procdesc["step"] is not None:
self.setSingleStep(procdesc["step"])
if procdesc["min"] is not None:
self.setMinimum(procdesc["min"])
if procdesc["max"] is not None:
self.setMinimum(procdesc["max"])
if procdesc["unit"]:
self.setSuffix(" " + procdesc["unit"])
if "default" in procdesc:
self.setValue(procdesc["default"])

def get_argument_value(self):
return self.value()


class _StringEntry(QtGui.QLineEdit):
def __init__(self, procdesc):
QtGui.QLineEdit.__init__(self)
if "default" in procdesc:
self.insert(procdesc["default"])

def get_argument_value(self):
return self.text()


_procty_to_entry = {
"FreeValue": _FreeValueEntry
"FreeValue": _FreeValueEntry,
"BooleanValue": _BooleanEntry,
"EnumerationValue": _EnumerationEntry,
"NumberValue": _NumberEntry,
"StringValue": _StringEntry
}


106 changes: 103 additions & 3 deletions artiq/language/environment.py
Original file line number Diff line number Diff line change
@@ -2,7 +2,10 @@
from inspect import isclass


__all__ = ["NoDefault", "FreeValue", "HasEnvironment",
__all__ = ["NoDefault",
"FreeValue", "BooleanValue", "EnumerationValue",
"NumberValue", "StringValue",
"HasEnvironment",
"Experiment", "EnvExperiment", "is_experiment"]


@@ -17,7 +20,7 @@ class DefaultMissing(Exception):
pass


class FreeValue:
class _SimpleArgProcessor:
def __init__(self, default=NoDefault):
if default is not NoDefault:
self.default_value = default
@@ -31,12 +34,72 @@ def process(self, x):
return x

def describe(self):
d = {"ty": "FreeValue"}
d = {"ty": self.__class__.__name__}
if hasattr(self, "default_value"):
d["default"] = self.default_value
return d


class FreeValue(_SimpleArgProcessor):
"""An argument that can be an arbitrary Python value."""
pass


class BooleanValue(_SimpleArgProcessor):
"""A boolean argument."""
pass


class EnumerationValue(_SimpleArgProcessor):
"""An argument that can take a string value among a predefined set of
values.
:param choices: A list of string representing the possible values of the
argument.
"""
def __init__(self, choices, default=NoDefault):
_SimpleArgProcessor.__init__(self, default)
assert default is NoDefault or default in choices
self.choices = choices

def describe(self):
d = _SimpleArgProcessor.describe(self)
d["choices"] = self.choices
return d


class NumberValue(_SimpleArgProcessor):
"""An argument that can take a numerical value (typically floating point).
:param unit: A string representing the unit of the value, for user
interface (UI) purposes.
:param step: The step with with the value should be modified by up/down
buttons in a UI.
:param min: The minimum value of the argument.
:param max: The maximum value of the argument.
"""
def __init__(self, default=NoDefault, unit="", step=None,
min=None, max=None):
_SimpleArgProcessor.__init__(self, default)
self.unit = unit
self.step = step
self.min = min
self.max = max

def describe(self):
d = _SimpleArgProcessor.describe(self)
d["unit"] = self.unit
d["step"] = self.step
d["min"] = self.min
d["max"] = self.max
return d


class StringValue(_SimpleArgProcessor):
"""A string argument."""
pass


class HasEnvironment:
"""Provides methods to manage the environment of an experiment (devices,
parameters, results, arguments)."""
@@ -60,12 +123,25 @@ def __init__(self, dmgr=None, pdb=None, rdb=None, *,
del self.__kwargs

def build(self):
"""Must be implemented by the user to request arguments.
Other initialization steps such as requesting devices and parameters
or initializing real-time results may also be performed here.
When the repository is scanned, any requested devices and parameters
are set to ``None``."""
raise NotImplementedError

def dbs(self):
return self.__dmgr, self.__pdb, self.__rdb

def get_argument(self, key, processor=None):
"""Retrieves and returns the value of an argument.
:param key: Name of the argument.
:param processor: A description of how to process the argument, such
as instances of ``BooleanValue`` and ``NumberValue``.
"""
if not self.__in_build:
raise TypeError("get_argument() should only "
"be called from build()")
@@ -85,17 +161,23 @@ def get_argument(self, key, processor=None):
return processor.process(argval)

def attr_argument(self, key, processor=None):
"""Sets an argument as attribute. The names of the argument and of the
attribute are the same."""
setattr(self, key, self.get_argument(key, processor))

def get_device(self, key):
"""Creates and returns a device driver."""
if self.__dmgr is None:
raise ValueError("Device manager not present")
return self.__dmgr.get(key)

def attr_device(self, key):
"""Sets a device driver as attribute. The names of the device driver
and of the attribute are the same."""
setattr(self, key, self.get_device(key))

def get_parameter(self, key, default=NoDefault):
"""Retrieves and returns a parameter."""
if self.__pdb is None:
raise ValueError("Parameter database not present")
if key in self.__param_override:
@@ -109,14 +191,24 @@ def get_parameter(self, key, default=NoDefault):
raise

def attr_parameter(self, key, default=NoDefault):
"""Sets a parameter as attribute. The names of the argument and of the
parameter are the same."""
setattr(self, key, self.get_parameter(key, default))

def set_parameter(self, key, value):
"""Writes the value of a parameter into the parameter database."""
if self.__pdb is None:
raise ValueError("Parameter database not present")
self.__pdb.set(key, value)

def set_result(self, key, value, realtime=False):
"""Writes the value of a result.
:param realtime: Marks the result as real-time, making it immediately
available to clients such as the user interface. Returns a
``Notifier`` instance that can be used to modify mutable results
(such as lists) and synchronize the modifications with the clients.
"""
if self.__rdb is None:
raise ValueError("Result database not present")
if realtime:
@@ -132,9 +224,17 @@ def set_result(self, key, value, realtime=False):
self.__rdb.nrt[key] = value

def attr_rtresult(self, key, init_value):
"""Writes the value of a real-time result and sets the corresponding
``Notifier`` as attribute. The names of the result and of the
attribute are the same."""
setattr(self, key, set_result(key, init_value, True))

def get_result(self, key):
"""Retrieves the value of a result.
There is no difference between real-time and non-real-time results
(this function does not return ``Notifier`` instances).
"""
if self.__rdb is None:
raise ValueError("Result database not present")
return self.__rdb.get(key)
18 changes: 18 additions & 0 deletions examples/master/repository/arguments_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from artiq import *


class ArgumentsDemo(EnvExperiment):
def build(self):
self.attr_argument("free_value", FreeValue(None))
self.attr_argument("boolean", BooleanValue(True))
self.attr_argument("enum", EnumerationValue(
["foo", "bar", "quux"], "foo"))
self.attr_argument("number", NumberValue(42, unit="s", step=0.1))
self.attr_argument("string", StringValue("Hello World"))

def run(self):
print(self.free_value)
print(self.boolean)
print(self.enum)
print(self.number)
print(self.string)