From 3cc11a511d606311aa3dfa0715cd2ec90bfd932a Mon Sep 17 00:00:00 2001 From: cQED-T3 Date: Mon, 30 Oct 2017 16:33:13 +0100 Subject: [PATCH 1/3] set_parser for seq element setting added --- qcodes/instrument_drivers/tektronix/AWG5014.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qcodes/instrument_drivers/tektronix/AWG5014.py b/qcodes/instrument_drivers/tektronix/AWG5014.py index 613f2b58c36..95c220cd190 100644 --- a/qcodes/instrument_drivers/tektronix/AWG5014.py +++ b/qcodes/instrument_drivers/tektronix/AWG5014.py @@ -212,7 +212,7 @@ def __init__(self, name, address, timeout=180, num_channels=4, **kwargs): label='Sequence position', get_cmd='AWGControl:SEQuencer:POSition?', set_cmd='SEQuence:JUMP:IMMediate {}', - vals=vals.Ints(1) + set_parser=int ) # Trigger parameters # From df68953c3090c08a3addabe187c70769d178219c Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Fri, 3 Nov 2017 11:31:06 +0100 Subject: [PATCH 2/3] Add Permissive int validator To be used for parameters that may be set as floats but should be cast to int --- qcodes/tests/test_parameter.py | 31 +++++++++++++++++++++++++++++++ qcodes/tests/test_validators.py | 27 ++++++++++++++++++++++++++- qcodes/utils/validators.py | 21 +++++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/qcodes/tests/test_parameter.py b/qcodes/tests/test_parameter.py index c827f20b1a2..57dc15caf87 100644 --- a/qcodes/tests/test_parameter.py +++ b/qcodes/tests/test_parameter.py @@ -5,6 +5,8 @@ from unittest import TestCase from time import sleep +import numpy as np + from qcodes import Function from qcodes.instrument.parameter import ( Parameter, ArrayParameter, MultiParameter, @@ -250,6 +252,35 @@ def test_latest_value(self): self.assertEqual(p.get_latest(), 21) self.assertEqual(p.get_values, [21]) + +class TestValsandParseParameter(TestCase): + + def setUp(self): + self.parameter = Parameter(name='foobar', + set_cmd=None, get_cmd=None, + set_parser=lambda x: int(round(x)), + vals=vals.PermissiveInts(0)) + + def test_setting_int_with_float(self): + + a = 0 + b = 10 + values = np.linspace(a, b, b-a+1) + for i in values: + self.parameter(i) + a = self.parameter() + assert isinstance(a, int) + + def test_setting_int_with_float_not_close(self): + + a = 0 + b = 10 + values = np.linspace(a, b, b-a+2) + for i in values[1:-2]: + with self.assertRaises(TypeError): + self.parameter(i) + + class SimpleArrayParam(ArrayParameter): def __init__(self, return_val, *args, **kwargs): self._return_val = return_val diff --git a/qcodes/tests/test_validators.py b/qcodes/tests/test_validators.py index 0f8b6712d04..0639a8af3f4 100644 --- a/qcodes/tests/test_validators.py +++ b/qcodes/tests/test_validators.py @@ -3,7 +3,8 @@ import numpy as np from qcodes.utils.validators import (Validator, Anything, Bool, Strings, - Numbers, Ints, Enum, MultiType, + Numbers, Ints, PermissiveInts, + Enum, MultiType, Arrays, Multiples, Lists, Callable, Dict) @@ -351,6 +352,30 @@ def test_failed_numbers(self): Ints(min_value=val) +class TestPermissiveInts(TestCase): + + + def test_close_to_ints(self): + validator = PermissiveInts() + a = 0 + b = 10 + values = np.linspace(a, b, b-a+1) + for i in values: + validator.validate(i) + + def test_bad_values(self): + validator = PermissiveInts(0, 10) + a = 0 + b = 10 + values = np.linspace(a, b, b-a+2) + for j,i in enumerate(values): + if j == 0 or j == 11: + validator.validate(i) + else: + with self.assertRaises(TypeError): + validator.validate(i) + + class TestEnum(TestCase): enums = [ [True, False], diff --git a/qcodes/utils/validators.py b/qcodes/utils/validators.py index f66f8256cca..395cf6555f4 100644 --- a/qcodes/utils/validators.py +++ b/qcodes/utils/validators.py @@ -217,6 +217,27 @@ def __repr__(self): maxv = self._max_value if self._max_value < BIGINT else None return ''.format(range_str(minv, maxv, 'v')) +class PermissiveInts(Ints): + """ + requires an integer or a float close to an integer + optional parameters min_value and max_value enforce + min_value <= value <= max_value + Note that you probably always want to use this with a + set_parser that converts the float repr to an actual int + """ + def validate(self, value, context=''): + if isinstance(value, (float, np.floating)): + intrepr = int(round(value)) + remainder = abs(value - intrepr) + if remainder < 1e-05: + castvalue = intrepr + else: + raise TypeError('{} is not an int or close to an int' + '; {}'.format(repr(value), context)) + else: + castvalue = value + super().validate(castvalue, context=context) + class Enum(Validator): """ From 4ed35c2e83bbce6b5801b29472ebbf39c3b4a118 Mon Sep 17 00:00:00 2001 From: Jens Hedegaard Nielsen Date: Fri, 3 Nov 2017 11:31:26 +0100 Subject: [PATCH 3/3] Still validate this and parse it too --- qcodes/instrument_drivers/tektronix/AWG5014.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qcodes/instrument_drivers/tektronix/AWG5014.py b/qcodes/instrument_drivers/tektronix/AWG5014.py index 95c220cd190..b5988b68769 100644 --- a/qcodes/instrument_drivers/tektronix/AWG5014.py +++ b/qcodes/instrument_drivers/tektronix/AWG5014.py @@ -212,7 +212,8 @@ def __init__(self, name, address, timeout=180, num_channels=4, **kwargs): label='Sequence position', get_cmd='AWGControl:SEQuencer:POSition?', set_cmd='SEQuence:JUMP:IMMediate {}', - set_parser=int + vals=vals.PermissiveInts(1), + set_parser=lambda x: int(round(x)) ) # Trigger parameters #