Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 43 additions & 1 deletion qcodes/tests/test_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import numpy

from qcodes.utils.validators import (Validator, Anything, Bool, Strings,
Numbers, Ints, Enum, MultiType)
Numbers, Ints, Enum, Multiples, MultiType)


class AClass:
Expand Down Expand Up @@ -379,6 +379,48 @@ def test_bad(self):
Enum(*enum)


class TestMultiples(TestCase):
divisors = [3, 7, 11, 13]
not_divisors = [0, -1, -5, -1e15, 0.1, -0.1, 1.0, 3.5, -2.3e6, 5.5e15, 1.34e-10, -2.5e-5,
math.pi, math.e, '', None, float("nan"), float("inf"),
-float("inf"), '1', [], {}, [1, 2], {1: 1}, b'good',
AClass, AClass(), a_func]
multiples = [0, 1, 10, -1, 100, 1000000, int(-1e15), int(1e15),
# warning: True==1 and False==0 - we *could* prohibit these, using
# isinstance(v, bool)
True, False,
# numpy scalars
numpy.int64(2)]
not_multiples = [0.1, -0.1, 1.0, 3.5, -2.3e6, 5.5e15, 1.34e-10, -2.5e-5,
math.pi, math.e, '', None, float("nan"), float("inf"),
-float("inf"), '1', [], {}, [1, 2], {1: 1}, b'good',
AClass, AClass(), a_func]

def test_divisors(self):
for d in self.divisors:
n = Multiples(divisor=d)
for v in [d * e for e in self.multiples]:
n.validate(v)

for v in self.multiples:
if v == 0:
continue
with self.assertRaises(ValueError):
n.validate(v)

for v in self.not_multiples:
with self.assertRaises(TypeError):
n.validate(v)

for d in self.not_divisors:
with self.assertRaises(TypeError):
n = Multiples(divisor=d)

n = Multiples(divisor=3, min_value=1, max_value=10)
self.assertEqual(
repr(n), '<Ints 1<=v<=10, Multiples of 3>')


class TestMultiType(TestCase):
def test_good(self):
m = MultiType(Strings(2, 4), Ints(10, 1000))
Expand Down
30 changes: 30 additions & 0 deletions qcodes/utils/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,36 @@ def validate(self, value, context=''):
return self._validator.validate(value, context)


class Multiples(Ints):
"""
A validator that checks if a value is an integer multiple of a fixed devisor
This class extends validators.Ints such that the value is also checked for
being integer between an optional min_value and max_value. Furthermore this
validator checks that the value is an integer multiple of an fixed, integer
divisor. (i.e. value % divisor == 0)
Args:
divisor (integer), the value need the be a multiple of this divisor
Inherited Args (see validators.Ints):
max_value, value must be <= max_value
min_value, value must be >= min_value
"""

def __init__(self, divisor=1, **kwargs):
super().__init__(**kwargs)
if not isinstance(divisor, int) or divisor <= 0:
raise TypeError('divisor must be a positive integer')
self._divisor = divisor

def validate(self, value, context=''):
super().validate(value=value, context=context)
if not value % self._divisor == 0:
raise ValueError('{} is not a multiple of {}; {}'.format(
repr(value), repr(self._divisor), context))

def __repr__(self):
return super().__repr__()[:-1] + ', Multiples of {}>'.format(self._divisor)


class MultiType(Validator):
"""
allow the union of several different validators
Expand Down